{ "cells": [ { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "# Relationale Algebra mit reframe*\n", "\n", "Der Zweck dieses Notebooks ist [reframe](https://github.com/bnmnetp/reframe) einzuführen. Dies ist eine Python Bibliothek, welche es uns ermöglicht Relationale Algebra interaktiv zu üben.\n", "\n", "#### Hinweis: Diese Einführung, die Aufgaben zu reframe und reframe generell sind nicht prüfungsrelevant. Prüfungsrelevant ist der mathematische Syntax welcher in der Vorlesung eingeführt wurde. Dieses Notebook und jenes mit Aufgaben zu reframe ist nur zur interaktiven Eigenübung für Sie gedacht." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "Los gehts!\n", "Zuerst definieren wir eine Relation und benutzen als Eingabe die beigefügte CSV Datei.\n", "Durch einen Relationale-Algebra-Ausdruck werden aus existierenden Relationen neue Relationen gebildet." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "from reframe import Relation\n", "\n", "country = Relation(\"../resources/05_relationale_algebra/country.csv\")\n", "country" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Selektion\n", "\n", "Die Selektion (σ) begrenzt die Tupel der Eingaberelation anhand des gegebenen Prädikats.\n", "Wir wollen jetzt die Länder ausgeben lassen, welche sich in Asien oder Europa befinden.\n", "\n", "$\\LARGE \\sigma_{continent = \"Asia\" \\lor continent = \"Europe\"} (country)$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.select('continent==\"Asia\" | continent==\"Europe\"')" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Projektion \n", "\n", "Die Projektion (π) begrenzt die Attribute der Eingaberelation, anhand der gegebenen Attributnamen.\n", "In unserem Beispiel wollen wir nun nur den Ländercode, Namen und Kontinent der Länder, die sich entweder in Asien oder Europa befinden, ausgeben lassen.\n", "\n", "$\\LARGE \\sigma_{continent = \"Asia\" \\lor continent = \"Europe\"}(\\pi_{code, name, continent}(country))$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.project([\"code\", \"name\", \"continent\"]).select('continent==\"Asia\" | continent==\"Europe\"')" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "Die Reihenfolge dieser Operationen spielt keine Rolle, die folgende Anfrage liefert dasselbe Ergebnis.\n", "\n", "$\\LARGE \\pi_{code, name, continent}(\\sigma_{continent = \"Asia\"\\lor continent = \"Europe\"}(country))$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.select('continent==\"Asia\" | continent==\"Europe\"').project([\"code\", \"name\", \"continent\"])" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Umbenennung\n", "\n", "Die Umbenennung (ρ) erlaubt es, ein oder mehrere Attribute umzubenennen. Dies kann notwendig werden, wenn wir identische Schemata für Mengen-Operatoren benötigen oder auch identisch benannte Felder für einen natürlichen (natural) join. \n", "\n", "Unten haben wir die vorherige Anfrage, der wir jedoch noch eine Umbenennung hinzufügen, sodass die Spalte `name` zu `Land` umbenannt wird. \n", "\n", "$\\LARGE \\rho_{code, Land, continent}(\\sigma_{continent = \"Asia\" \\lor continent = \"Europe\"}(\\pi_{code, name, continent}(country)))$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.select('continent==\"Asia\" | continent==\"Europe\"').project(\n", " [\"code\", \"name\", \"continent\"]\n", ").rename(\"name\", \"Land\")" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Differenz\n", "\n", "Bisher haben wir unäre Operatoren betrachtet, welche eine Relation als Eingabe erhalten. Nun betrachten wir binäre Operationen, welche genau zwei Relationen als Eingabe erhalten. Die Differenz (-) erlaubt es, die Differenz von zwei Relationen zu berechnen. Die Differenz entfernt somit alle Instanzen der einen Relation, welche in der anderen Relation. Folgender Ausdruck gibt alle Länder, die nicht zu Asien gehören, zurück.\n", "\n", "$\\LARGE country - (\\sigma_{continent = \"Asia\"}(country))$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "asia = country.select('continent==\"Asia\"')\n", "\n", "country.minus(asia)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Vereinigung \n", "\n", "Die Vereinigung (∪) erlaubt es, die Instanzen von zwei Relationen zu vereinigen. Folgender Ausdruck gibt die Länder, die zu Europa und Asien gehören, zurück.\n", "\n", "$\\LARGE (\\sigma_{continent = \"Europe}(country)) \\cup (\\sigma_{continent=\"Asia\"}(country))$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "asia = country.select('continent==\"Asia\"')\n", "europe = country.select('continent==\"Europe\"')\n", "\n", "asia.union(europe)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Kreuzprodukt \n", "\n", "Mit dem Kreuzprodukt (⨯) werden alle Instanzen einer Relation mit allen Instanzen der anderen Relation kombiniert. Dafür definieren wir eine neue Relation country_stats, welche wie folgt aussieht: \n", "\n", "$\\LARGE country \\times country\\_ stats$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country_stats = Relation(\"../resources/05_relationale_algebra/country_stats.csv\")\n", "country.cartesian_product(country_stats)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Natürlicher/Natural Join \n", "\n", "Der Natural Join ($\\bowtie$) erhält zwei Relationen als Eingabe, welche namentlich in einem oder mehreren Attributen übereinstimmen und gibt eine neue Relation mit den Tupeln zurück, bei denen die Werte des oder der gemeinsamen Attribute übereinstimmen. Der Natural Join ist somit ein Kreuzprodukt mit einer Selektion. \n", "\n", "Folgender Ausdruck fügt also die Informationen bzw. Daten aus `country` und `country_stats` zusammen. \n", "\n", "$\\LARGE country \\bowtie country\\_ stats$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.njoin(country_stats)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Theta-Join \n", "\n", "Der Theta-Join ist ein erweiterter Operator, welcher auf keine identisch benannten Attribute benötigt; stattdessen werden die Attribute, in denen die Werte der Instanzen übereinstimmen müssen, explizit angegeben.\n", "\n", "$\\LARGE country \\bowtie_{code = code}country\\_ stats$\n", "\n", "In folgendem Ausdruck wird ein kartesisches Produkt mit einer Selektion benutzt und wir erhalten das selbe Ergebnis wie oben.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.cartesian_product(country_stats.rename(\"code\", \"countrycode\")).select(\n", " \"code == countrycode\"\n", ").project(\n", " [\n", " \"code\",\n", " \"name\",\n", " \"continent\",\n", " \"region\",\n", " \"surfacearea\",\n", " \"indepyear\",\n", " \"population\",\n", " \"lifeexpectancy\",\n", " \"gnp\",\n", " \"gnpold\",\n", " \"localname\",\n", " \"governmentform\",\n", " \"headofstate\",\n", " \"capital\",\n", " \"code2\",\n", " ]\n", ")" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Schnittmenge/Intersection\n", "\n", "Die Intersection erlaubt es, die Schnittmenge zweier Mengen bzw. Relationen zu bilden, also eine neue Menge, die nur aus den Instanzen besteht, die in beiden Ausgangsrelationen existieren. \n", "\n", "Im untenstehenden Beispiel bilden wir die Menge, in der nur Instanzen bzw. Länder existieren, deren Bevölkerung höher als 80 Millionen ist und wo die Lebenserwartung der Bevölkerung höher als 60 Jahre ist.\n", "\n", "$\\LARGE (\\sigma_{lifeexpectancy > 60}(country\\_ stats)) \\cap (\\sigma_{population > 80000000(country\\_stats)})$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "highlifeexp = country_stats.select(\"lifeexpectancy > 60\")\n", "largepopulation = country_stats.select(\"population > 80000000\")\n", "\n", "highlifeexp.intersect(largepopulation)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Aggregationen\n", "\n", "Ungruppierte Aggregationen erlauben es, Aggregate wie COUNT, MIN(imum), MAX(imum), SUM(me) oder AVG (Durschnitt) auf Relationen zu berechnen.\n", "Im nächsten Beispiel wollen wir die Anzahl der Tupel unserer Relation berechnen:\n", "\n", "$\\LARGE country.COUNT(*)$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.count()" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Gruppierung \n", "\n", "Die Gruppierung (γ) erlaubt es, die Instanzen einer Eingaberelation in Abhängigkeit von einem oder mehreren Gruppierungsattributen in Partitionen zu unterteilen, damit dann meist darauf Aggregationen berechnet werden können, pro Partition. \n", "\n", "Im unten stehenden Beispiel berechnen wir die Anzahl der Länder in jedem Kontinent.\n", "\n", "$\\LARGE \\gamma_{continent, COUNT(code)}(country)$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.groupby(\"continent\").count(\"code\")" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "#### Komplexe Ausdrücke \n", "\n", "Mittels der zuvor vorgestellten Operatoren lassen sich zunehmend komplexe Ausdrücke bilden, die es ermöglichen, die Daten beliebig zu manipulieren und abzufragen. \n", "\n", "Im unten stehenden Beispiel bestimmen wir den Ländercode und die Fläche des Landes mit der kleinsten Fläche. \n", "\n", "$\\large \\pi_{code, surfacearea}(\\sigma_{min = surfacearea}(((country \\bowtie country\\_ stats)MIN(surfacearea)) \\times country\\_ stats))$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "country.njoin(country_stats).min(\"surfacearea\").cartesian_product(country_stats).select(\n", " \"min==surfacearea\"\n", ").project([\"code\", \"surfacearea\"])" ] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 4 }