Leopold-Franzens-Universität Innsbruck Institut für Informatik Datenbanken und Informationssysteme B-Baum-Tool Erweiterung und Redesign Bachelor-Arbeit Felix Putz betreut von Prof. Dr. Günther Specht MSc PhD Michael Tschuggnall Innsbruck, 7. November 2016 Zusammenfassung Im Zuge der Optimierung von Datenbankanwendungen auf Festplatten gewannen speziell dafür entwickelte Datenstrukturen wie B-Bäume zunehmend an Bedeutung. Es lassen sich damit nicht nur Datenabfragen verkürzen, sondern auch abschätzen. Eine Datenbankanwendung kann somit gezielter auf Anforderungen, und in Verbindung mit der benötigten Hardware aufgebaut werden. In dieser Arbeit wird ein webbasiertes Tool entwickelt, welches die Operationen und Besonderheiten von B-Bäumen verständlich zu visualisieren versucht. Dabei wird zum Verständnis zuerst eine Einführung mit Hintergrundinformationen gegeben, und folgend typische Operationen auf B-Bäume beispielhaft erklärt. Die zweite Hälfte der Arbeit beschäftigt sich hauptsächlich mit der Programmierung, die Schritt für Schritt aufgebaut wird. Zahlreiche Beispiele und Anmerkungen verdeutlichen die Vorgehensweise und komplexere Inhalte. Danksagung III Vorwort Diese Arbeit soll eine solide Einführung rund um die Idee bis zur programmierten Umsetzung der B-Bäume geben. Dabei werden komplizierte Teilbereiche durch Hintergrundinformationen und Bildern Schritt für Schritt erklärt. Zudem sind Abkürzungen und schwierige Begriffe, die im Laufe der Arbeit eingeführt werden, durch Unterstrich markiert, und in einem Glossar mit kurzer Beschreibung zusammengefasst. So soll dem Leser ein besonders leichter und schneller Einstieg zu den Inhalten gelingen. Im Besonderen wird parallel zu dieser Arbeit ein webbasiertes-Tool entwickelt, welches auch Studenten zum Zwecke des Lernerfolgs dienen soll. Ich bin der Überzeugung, dass Interessenten mit dieser Arbeit sehr entsprochen werden kann, lege aber darüber hinaus auch ein gewisses Engagement zur eigenen Übung Nahe, um sich in diesem Teilgebiet der Informatik selbst festigen zu können. V Inhaltsverzeichnis 1 Einleitung 1 2 Definition (Varianten) der 2.1 B-Baum nach Bayer . . 2.2 B+-Baum . . . . . . . . 2.3 B*-Baum . . . . . . . . B-Bäume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Operationen 3.1 Search . . . . . . . . . . 3.2 Insert . . . . . . . . . . 3.3 Delete . . . . . . . . . . 3.4 Laufzeit für Datenzugriff 3.4.1 Vereinfachung 1 3.4.2 Vereinfachung 2 - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Laufzeitverhalten Laufzeitverhalten 4 B-Baum-Tool 4.1 Analytische Vorbereitung . . . . . . . . . . 4.1.1 Ziel . . . . . . . . . . . . . . . . . . 4.1.2 Problemstellung . . . . . . . . . . . 4.1.3 Anforderungen . . . . . . . . . . . . 4.2 Ausarbeitung . . . . . . . . . . . . . . . . . 4.2.1 Server und Verzeichnisbaum . . . . . 4.2.2 Der B-Baum in JavaScript . . . . . . 4.2.3 Die grafische Darstellung . . . . . . 4.2.4 Transformationen und Animationen 4.3 Benutzerschnittstelle (GUI) . . . . . . . . . 4.3.1 Laden von Beispielbäumen . . . . . 4.3.2 Erstellen eines neuen Baumes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 4 4 . . . . . . 5 . 5 . 6 . 7 . 10 . 12 . 12 . . . . . . . . . . . . 15 15 15 15 16 16 17 18 18 20 22 23 25 . . . . . . . . . . . . 5 Auswertung und Ausblick 29 Glossar 30 Literaturverzeichnis 31 VII Kapitel 1 Einleitung Vor allem Datenbanken sind auf ein schnelles Abgreifen von benötigten Daten angewiesen, um Abfragezeiten möglichst kurz zu halten. Meist sind Datenbanken jedoch zu groß, um sie in einen schnellen flüchtigen Speicher laden zu können. Auch wenn über die Jahre ein Plattenzugriff etwas schneller geworden ist, erreicht man heute kaum Zugriffszeiten von 10 Millisekunden. [BZ13] Dies ist die benötigte Zeit, um den Lesekopf in die richtige Spur zu positionieren, und dort auf das Eintreffen der Daten auf der drehenden Platte zu warten. Im Vergleich zum Arbeitsspeicher, wo ein Zugriff etwa 25 Nanosekunden braucht, ist eine Festplatte dabei um 400.000 mal langsamer. Um auf Daten im Festspeicher effizienter zugreifen zu können, musste deshalb eine Strategie entwickelt werden, diese Daten so abzuspeichern, damit diese Schwäche des Festspeichers minimiert wird. Die Idee war es, eine Indexstruktur zu entwerfen, die sich möglichst gut an den Festspeicher anpassen lässt, um die Anzahl der Datenzugriffe klein zu halten. Dazu entwickelten Rudolf Bayer und Edward M. McCreight den B-Baum [Bay72]. Dessen Knoten lassen sich auf die Seiten einer Festplatte, welche in einem Schritt gelesen werden, abbilden. Eine weitere Besonderheit des B-Baumes ist seine Eigenschaft ”nach oben zu wachsen”, wodurch er auch seine balancierte Struktur behält. Je nach Datenfülle lässt sich dann die Anzahl an Seitenzugriffen abschätzen. Kategorisch ist ein B-Baum eine Indexstruktur; im Besonderen ein balancierter Suchbaum. Eine Indexstruktur ist eine spezielle Anordnung von Daten, die mit Hilfe eines gewählten Suchkriteriums schneller gefunden werden können. Ein Beispiel dafür wäre eine Mitarbeiterkartei, wobei die Nachnamen nach dem Anfangsbuchstaben sortiert sind. Eine Suche nach einem bestimmten Buchstaben öffnet dann die richtige Stelle in der Kartei, wo alle Mitarbeiter mit gewähltem Anfangsbuchstaben vorliegen. Ein Suchbaum ist eine Datenstruktur die, wie der Name erahnen lässt, baumförmig angeordnet ist. Man stelle sich den Baum 1 KAPITEL 1. EINLEITUNG kopfüber hängend vom Wurzelstamm bis zu den Blättern vor. Dabei sind die Wege bis zu den Blättern durch “Schlüssel“ verbunden, die den richtigen Weg (Referenz) zu den gesuchten Daten zeigen. Es kann jedoch bald zu einem Ungleichgewicht kommen, wenn sich ähnliche Daten (nach Suchkriterium) gehäuft in nahem Umfeld einfügen. Eine Suche lässt sich dann nicht mehr genauer abschätzen, und effizient durchführen. Um dem entgegenzuwirken kann man Bäume ausbalancieren, wobei jeder Datensatz dann nach gewissen Schritten gefunden wird. Unterteilen lassen sich B-Bäume beispielsweise in der minimal geforderten Datenbelegung, und der Möglichkeit die Daten auszulagern. In den ersten Jahren wurden diese Variationen von unterschiedlichen Autoren als B+ und B* -Bäume mit unterschiedlichen Kriterien zusammengefasst. 1979 wurden diese dann von Douglas Comer [Com79] genauer voneinander abgegrenzt. Das National Institute of Standards and Technology (NIST) 1 nahm sich später dieser Beschreibungen an. Von den Autoren wurde der B-Baum begrifflich nicht näher erleutert. Über die Jahre spekulierte man für das ”B”mit Namen wie: ”balanced, broad, bushy”. Auch ”Boeing”wäre eine Möglichkeit, da Bayer und McCreight zur Entstehungszeit für Boeing in der Forschung tätig waren. Vielleicht ist es jedoch bei all diesen Interpretationen am sinnvollsten von ”Bayer”Bäumen zu sprechen, wie es bereits Douglas Comer vorschlug. Beispielhafter B-Baum 1 Offizielle Internetseite: https://www.nist.gov/ Publikationen lassen sich schnell und einfach über die Suche aufrufen. 2 Kapitel 2 Definition (Varianten) der B-Bäume 2.1 B-Baum nach Bayer Nach Rudolf Bayer wurde der B-Baum mit folgenden Anforderungen definiert [Bay72] : • Jeder Knoten des Baumes kann zwischen n und 2n Datensätze aufnehmen. Die Wurzel des Baumes ist davon ausgenommen. N steht dann für die Ordnung des Baumes. • Ein einzelner Datensatz besteht aus einem eindeutig bestimmten Schlüssel und dem eigentlichen Datenteil. • Wenn m die Anzahl der tatsächlichen Datensätze eines Knotens ist, so hat er m+1 Nachfolgeknoten (Kindknoten). Ausgenommen sind die Knoten der untersten Ebene. Diese, man nennt sie Blätter oder Blattknoten, haben keine Nachfolger unter sich. Siehe Beispielbaum- Referenz. • Die Datensätze sind im Baum nach dem Schlüssel geordnet. In weiterer Folge ergeben sich verschiedene Möglichkeiten solch einen Baum umzusetzen. Beispielsweise müsste der Datenteil eine fixierte maximale Größe haben, damit alle Datensätze eines Knotens auf einer Seite Platz finden. Dies wäre mit einem kleinen Datenteil gut umsetzbar. Bei größerem Datenteil ist es hingegen vorteilhafter, wenn ein Datensatz nur eine Referenz (Pointer) zu dem eigentlichen Datenteil halten muss. Dadurch haben mehrere Schlüssel in einer Seite Platz, und der Baum weist eine geringere Höhe auf. Man beachte dabei, dass durch die Datenreferenzierung ein weiterer Seitensprung erforderlich wird. 3 KAPITEL 2. DEFINITION (VARIANTEN) DER B-BÄUME 2.2 B+-Baum Eine andere Variante des B-Baumes stellt der B+-Baum dar [KE09]. Sein Ziel ist es den Aufbau so zu verändern, damit häufige Abfragen auf nachliegende Datenbereiche ohne ein erneutes Durchlaufen des Baumes möglich ist. Eine mögliche Frage wäre: ”Gib mir alle Namen aus, die zwischen Bayer und McCreight liegen!”. Dazu müssen sämtliche Datensätze auf die unterste Ebene ausgelagert werden. Diese Knoten in der Blattebene werden dann als doppelt verkettete Liste verknüpft. Der Baum selbst behält im Durchlauf nur mehr den Schlüsselteil für eine effiziente Suche bis zu den Datensätzen. Entnommen aus [Sch13] 2.3 B*-Baum Bei dieser Form des B-Baums setzt man auf einen höheren Füllgrad der einzelnen Knoten. Dabei muss beispielsweise ein Knoten mindestens mehr als 3/4 befüllt sein. Man erhofft sich dadurch ein Flacher-Werden des Baumes, und dadurch eine Minderung an Seitenzugriffen. Allerdings werden die Operationen komplizierter, und bei ungeschickt hoher Wahl des Füllgrads eine öfter auftretende und eventuell weitreichendere Umstrukturierung des Baumes notwendig. 4 Kapitel 3 Operationen 3.1 Search Die Suche nach einem Datensatz erfolgt mit Hilfe des Schlüssels, welcher dem eigentlichen Datenteil zugeordnet ist. Da die Schlüssel geordnet vorliegen, lassen sich folgende Regeln definieren: 1. Lese Wurzelknoten. 2. Suche KEY in aktuellem Knoten. • Wenn gefunden, dann gib Datensatz aus. ENDE. • Wenn nicht gefunden, bestimme nächsten Kindknoten. – Nächster Kindknoten ist NULL. KEY nicht gefunden. ENDE. – Lese Kindknoten, und gehe zu Punkt 2. Der Pfad für einen typischen Durchlauf veranschaulicht den Such-Algorithmus, und ist von der Wurzel beginnend in gelber Farbe hervorgehoben: Die Suche nach dem Schlüsseleintrag 15. Dabei wird der Wurzelknoten gelesen, und Eintrag 32 mit 15 verglichen. 15 ist kleiner als 32, so wird im linken Kindknoten weiter gesucht. Da 15 größer ist als 11, wird zum rechten Nachbarelement weiter gegangen. 15 ist kleiner als 17, so wird in seinem linken Kindknoten weiter gesucht. In diesem Knoten wurde 15 gefunden. 5 KAPITEL 3. OPERATIONEN 3.2 Insert Beim Einfügen eines Schlüssels entsteht ein Knotenüberlauf, sobald die Vereinbarung für die Maximalanzahl an erlaubten Elementen im Knoten (2n) überschritten wird. Die anschließende Behandlung lässt den Baum von unten nach oben wachsen. 1. Suche KEY im Baum • Wenn gefunden, dann breche ab. ENDE. • Wenn nicht gefunden, bleibe bei Knoten. 2. Füge KEY in Knoten ein. 3. Prüfe, ob Anzahl an Datensätzen <2n • Ja, kein Überlauf. ENDE. • Nein, Überlauf. – Wähle KEYn+1 (mittlerer Schlüssel). – Hänge linke, und rechte Schlüssel im Knoten als linken und rechten Kindknoten an KEYn+1 an. – Füge KEYn+1 in Elternknoten ein, und gehe zu Punkt 3. Wie beschriebener Knotensplit funktioniert, wird im folgenden veranschaulicht. Überlaufbehandlung Man nehme wieder den selben Baum, wie bereits für die Schlüsselsuche eingeführt. Der Fokus wird hierbei auf den linken Teilbaum gelegt. Um einen Überlauf zu provozieren, wird der Schlüssel 9 eingefügt. Da nun der Knoten mit 2,6,8,9,10 mehr als 2n Einträge hat, wird der Knotensplit als Überlaufbehandlung durchgeführt. Dazu wird das mittlere Element 8 gewählt, und seine linken und rechten Schlüsselnachbarn ihm als Kindknoten angehängt. Anschließend wird die 8 als Elternelement im Elternknoten eingefügt. Der daraus entstandene Teilbaum sieht wie folgt aus: −→ 6 KAPITEL 3. OPERATIONEN 3.3 Delete Vor dem Löschen müssen zuerst ein paar Vereinbarungen definiert werden. Denn gelöschte Positionen müssen meist durch andere Elemente besetzt werden, um die Baumintegrität zu bewahren. Dabei sollte klar sein, wo solch ein Schlüssel zu suchen ist. Auch sind manchmal Umstrukturierungen notwendig, wobei fest stehen sollte, in welche Richtung sich diese orientieren. Der grundlegende Algorithmus wird nun eingeführt. 1. Suche KEY im Baum • Wenn nicht gefunden, dann breche ab. ENDE. • Wenn gefunden, bleibe bei Knoten. 2. Lösche KEY aus Knoten. • Wenn Knoten ist Elternknoten. – Ersetze KEY-Position durch nächstkleineres oder nächstgrößeres Element der Kindknoten. (Ordne dessen Kind richtig ein!) – Setze Kindknoten als aktuellen Knoten. 3. Prüfe auf Unterlauf • Wenn Anzahl an Elemente >n. ENDE. 4. Unterlaufbehandlung • Knoten hat Nachbarknoten mit genau n Einträgen – Zusammenfassen mit dem Nachbarknoten und gemeinsamen Elternelement. – Setze für diesen Elternknoten bei Punkt 3 fort. • Ansonsten führe Rotation durch. – Wähle linken oder rechten Nachbarknoten für Rotation. – Verschiebe gemeinsames Elternelement in aktuellen Knoten. – Ersetze ursprüngliche Position des Elternelements durch sein nächst-kleineres bzw. nächst-größeres Element des gewählten Nachbarknoten. Es wurde bewusst die Möglichkeit für die Entscheidungen nach links oder rechts offen gelassen. Man könnte nun den Algorithmus dahingehend verbessern, indem bei Entscheidungssituationen beide Wege in Betracht gezogen werden. Würde beim Löschen in einem Elternknoten das 7 KAPITEL 3. OPERATIONEN nächstkleinere Element einen Unterlauf provozieren, könnte stattdessen auch beim Nächstgrößeren nachgesehen werden, wo dies nicht der Fall sein könnte. Ähnliche Vorgehensweise wäre auch für die Unterlaufbehandlung eine Optimierung, die größere Umstrukturierungen vermeiden könnte. Zur Verdeutlichung werden nun repräsentative Beispiele für den Löschalgorithmus gezeigt, um Besonderheiten hervorzuheben. Es wird vom selben Baum ausgegangen, welcher bereits bei der Suche eingeführt wurde. Löschen in Elternknoten Der Schlüssel 11 soll gelöscht werden. Nach der erfolgreichen Suche wird sich seine Position gemerkt, und anschließend das nächstkleinere Element in seinem linken Teilbaum gesucht. Somit wurde 10 bestimmt, und anstelle des gelöschten Schlüssels eingetragen. −→ Unterlaufbehandlung durch Zusammenfassen Durch Knotenzusammenfassungen sind auch Höhenschrumpfungen möglich: Ein Löschen von Schlüssel 40, und anschließend 48, bewirkt im rechten Teilbaum ein Zusammenfassen beider Knoten. 8 KAPITEL 3. OPERATIONEN Dabei wird das gemeinsame Elternelement 44 miteinsortiert. Dadurch entsteht ein erneuter Unterlauf mit darauffolgendem Zusammenfassen. Der gemeinsame elterliche Schlüssel ist 32. Dieser wird mit den anderen zusammengelegt, wodurch sich der Baum in der Höhe vermindert: Unterlaufbehandlung durch Rotation Lassen sich keine Nachbarn mit genau n Elementen finden, wird eine Rotation durchgeführt. Um solche Situation herbeizuführen, wird dem Baum, wie bereits bei der Einfüge-Operation getan, der Schlüssel 9 hinzugefügt. Man erhält dadurch folgenden Baum: Anschließend wird 48 gelöscht, und eine Rotation vom rechten Nachbarknoten nach links durchgeführt. Dabei bekommt der unterlaufene Knoten das gemeinsame Elternelement 49, und auf seiner ursprünglichen Position durch das nächstgrößere Kindelement ersetzt. Hierbei muss9 KAPITEL 3. OPERATIONEN ten keine Teilbäume verschoben werden, da die Rotation auf Blattebene stattfand. Um nun eine Rotation zu provozieren, wo auch Teilbäume umgehängt werden müssen, löscht man den Schlüssel 58. Denn das bewirkt ein Zusammenfassen mit Elternelement 50, wodurch dieser Elternknoten dann eine Unterlaufbehandlung durchführen muss. Wie in der Abbildung hervorgehoben, wird eine Rotation vom linken Nachbarknoten nach rechts durchgeführt. Man beachte das richtige Einordnen des kindlichen Teilbaums (hier: Knoten auf Blattebene). 3.4 Laufzeit für Datenzugriff Die entstehenden Kosten für das Auffinden und Zugreifen auf einen Datensatz werden hier am Beispiel der Suchfunktion gezeigt. Grundsätzlich berechnet sich solch eine Abschätzung durch die Anzahl an Knotenzugriffen innerhalb des Baumes, sowie dem schlussendlichen Zugriff auf die gesuchten Daten, und der dafür jeweils benötigten Speicherzugriffszeit. Hierfür wird angenommen, dass ein Knoten unter einmal vollständig eingelesen werden kann. Die Anzahl an Knotenzugriffen richtet sich 10 KAPITEL 3. OPERATIONEN nach der Höhe h des Baumes. Diese ist im wesentlichen Abhängig vom Verzweigungsgrad. Wenn man von einer Minimalbelegung ausgeht, entspricht der Verzweigungsgrad der Ordnung des Baumes, plus einem weiteren Kindknoten. Wie viele Datensätze ein Baum der Ordnung n und der Höhe h fasst, wird nun schrittweise berechnet: Auf der Ebene 0 befindet sich die Wurzel. Es wird 1 Knoten gezählt. Die Wurzel selbst verweist in nächster Ebene auf 2 Kindknoten. Ebene zwei umfasst folgend mindestens 2*(n+1)Knoten. Je nach Höhe des Baumes werden für jede weitere Ebene (n+1) Kindknoten dazu multipliziert. Es befinden sich demnach: 2*(n+1)h−1 Knoten auf einer beliebigen Ebene. Da sich, wie angenommen, in jedem Knoten genau n Datensätze befinden, gibt es: 2n*(n+1)h−1 Datensätze auf Ebene h. Um nun herauszufinden wie viele Datensätze ein Baum mindestens hat, müssen alle Ebenen aufsummiert werden. Somit gilt für die Wurzel, und alle Nachfolgeknoten: P 1+ hi=1 2n*(n+1)i−1 Durch Vereinfachung des Terms (siehe 3.4.1, Seite 12) erhält man: 2(n+1)h -1 Um nun herauszufinden, welche Höhe h ein minimal belegter B-Baum mit N Datensätze hat, setzt man N = 2(n+1)h -1 und erhält für die Höhe (siehe 3.4.2, Seite 12) log( N +1 ) 2 h = log(n+1) Diese theoretische Höhe entspricht nun einer Minimalbelegung, und muss noch auf die nächst-größere ganze Zahl aufgerundet werden, um die tatsächliche Höhe des B-Baums zu erhalten, wo alle Datensätze Platz finden. (Sofern die Höhe, wie in den meisten Fällen, keiner ganzen Zahl entspricht.) Ein Beispiel: Man nehme an, jeder Österreicher [SA16] steht im Telefonbuch, und dieses sei in einem B-Baum gespeichert. Wie viele Seitenzugriffe werden für die 8.700.471 Datensätze benötigt, wenn man von einer optimalen Seitengröße von 4kB ausgeht, wobei ein Indexeintrag 16B belegt? (Unter “optimal“ wird eine Knotengröße verstanden, die genau einer Speicherseite entspricht. Des weiteren ist für den Indexeintrag die weiterführende Referenz bereits inkludiert.) 11 KAPITEL 3. OPERATIONEN 3.4.1 Vereinfachung 1 - Laufzeitverhalten Um den Term zu vereinfachen, gleicht man die Summe der Ph i 1−z h+1 Lösungsformel der Geometrischen-Reihe an, und i=0 z = 1−z wendet diese dann an. 1+ hi=1 2n*(n+1)i−1 Herausziehen des Faktors 2n. P 1+2n* hi=1 (n+1)i−1 Angleichen der Summe. P i 1+2n* h−1 i=0 (n+1) Anwenden der Lösungsformel der Geometrischen-Reihe. (h−1)+1 1+2n* 1−(n+1) 1−(n+1) Durch Berechnung erhält man h 1+2n* 1−(n+1) −n Minus des Nenners aus dem Bruch nehmen, und n kürzen. 1+(-2*(1-(n+1)h )) Durch weiteres Berechnen erhält man 1-2+2(n+1)h Nach dem letzten Schritt kann nicht weiter vereinfacht werden, und man erhält: 2(n+1)h -1 P 3.4.2 Vereinfachung 2 - Laufzeitverhalten Gesucht ist die Höhe h. Man forme nun so um, bis h auf einer Seite der Gleichung steht. Da h als Exponent vorkommt, wird zur Hilfe der Logarithmus eingesetzt. (log zh = h* log z) N = 2(n+1)h -1 1 addieren, dann durch 2 dividieren. N +1 h 2 = (n+1) Logarithmus anwenden. log N 2+1 = h* log(n+1) Durch dividieren von log(n+1) erhält man h= 12 log( N2+1 ) log(n+1) KAPITEL 3. OPERATIONEN Zuerst berechnet man die Ordnung des Baumes. Die mögliche Anzahl an Einträgen in einer Seite ist demnach 4096 / 16 = 256 Und die Ordnung des Baumes ist somit n = 256 / 2 = 128 Durch Einsetzen in die erarbeitete Formel erhält man log( 8700471+1 ) 2 h = log(128+1) = 3, ... Auf die nächst-größere Zahl aufgerundet, beträgt die Höhe dieses Baumes 4. Man könnte nun sein Ergebnis überprüfen, und berechnet sich die Minimalbelegung für h=3, und h=4, wobei die beispielhafte Anzahl an Datensätze dazwischen liegen muss. 2(n+1)3 -1 ≤ N ≥ 2(n+1)4 -1 2(128+1)3 -1 ≤ 8700471 ≥ 2(128+1)4 -1 4.293.377 ≤ 8.700.471 ≥ 553.845.761 Somit stimmt die beispielhafte Berechnung. Wenn man nun davon ausgeht, dass sich die gesuchten Daten nicht direkt im Knoten des Baumes befinden, sondern dessen Referenzen, muss noch ein Seitenzugriff zur Baumhöhe dazu-addiert werden. Damit erhält man 5 Seitenzugriffe. Wie in der Einleitung beschrieben, könnte man mit Zugriffszeiten von 10 Millisekunden rechnen, dabei würde die beispielhafte Suche nach genau einem Telefonbucheintrag 50 Millisekunden dauern. 13 Kapitel 4 B-Baum-Tool 4.1 4.1.1 Analytische Vorbereitung Ziel Ziel dieser Arbeit ist es, ein webbasiertes Tool zu erstellen, welches für den universitären Einsatz verwendet werden kann. Im speziellen soll es zum Lernerfolg der Studierenden beitragen, indem die Funktionsweisen und Algorithmen interaktiv erklärt, und nachvollziehbar dargestellt werden. Dabei soll jeder einzelne Schritt veranschaulicht werden. Zudem können verschiedene Parameter, wie beispielsweise der Verzweigungsgrad (abhängig von der Ordnung des Baumes) eingestellt werden. Des weiteren werden vom Tool ganze Bäume nach ausgewählten Kriterien eigenständig generiert. Lehrreiche Beispielbäume können vom Administrator neu hinzugefügt, und vom Anwender nach Belieben abgerufen werden. Zur Unterstützung all dieser Funktionen werden Technologien ausgenützt, welche zur Usability und User-Experience beitragen. Dabei soll eine intuitive Bedienung erreicht werden, die das Benützen des Tool als Erlebnis abrundet. 4.1.2 Problemstellung Es muss ein Konsens zwischen den B-Baum-Algorithmen und der grafischen Darstellung gefunden werden. Zudem braucht die visuelle Ausgabe eine Schnittstelle für User-Interaktionen. Dazu wurde ein Prototyp des B-Baums erstellt, und darauf aufbauend ein Einsatz von Canvas, SVG, und reinem HTML ausgiebig miteinander verglichen. Auch sollen keine langen, und unnötigen Wartezeiten für den Anwender entstehen. Deshalb wäre es zudem vorteilhaft, eine Strategie für die grafische Ausgabe zu finden, um den Baumstatus nach durchgeführten Operationen dauerhaft zu erhalten, ohne den gesamten Baum stets neu aufbauen zu müssen. Sind dann erstmals die B-Baum-Algorithmen implementiert, 15 KAPITEL 4. B-BAUM-TOOL stellt es eine weitere Herausforderung dar, diese dem Anwender Schritt für Schritt animiert anzuzeigen. 4.1.3 Anforderungen Unter Einbeziehung der angeführten Ziele und der daraus folgenden Problemanalyse ergeben sich folgende Anforderungen an die Umsetzung des Systems: • Es wird ein PHP-Server installiert, der dem Client das Programm übermittelt. Gewisse administrative Einstellungen sind in einer config.php am Server hinterlegt. • Das Programm wird in JavaScript programmiert, und läuft am Client-Computer. • Der Baum wird dem Anwender durch geschickte Anordnung von DIV-Elementen visuell dargestellt. • Über die DOM-Schnittstelle ist ein ständiger Zugriff zwischen dem dargestellten, und dem in Javascript gehaltenen Baum möglich. • Ein Nachladen von Bäumen wird über AJAX realisiert, wobei diese als JSON-Objekte übertragen werden. • Für eine benutzerfreundliche Realisierung werden HTML- und CSSPatterns eingesetzt. Die einzelnen Begriffe sind im Glossar (siehe 5, Seite 30) mit kurzer Beschreibung aufgelistet. 4.2 Ausarbeitung Es gibt genug Hilfsmittel wie Code-Snippets, Bibliotheken, Frameworks, auch ganze Tools, die es einem einfacher machen, eine Web-App zu erstellen, oder diese sogar großteils generieren zu lassen. Bei Frameworks und generierten Anwendungen leidet darunter jedoch meistens die Qualität des Programms, und äußert sich in langen, und oft sinnlosen Ladezeiten für den User, sowie für den Programmierer in schwieriger Änderbarkeit durch Abhängigkeiten, und erschwerter Portabilität durch mögliche weitere Anforderungen an das System. Für Verbesserungen müsste man den Code ständig anpassen. Um von Anfang an ein leichtgewichtiges, qualitatives Tool zu erstellen, wurde von einem Überladen durch Hilfsmittel abgesehen, und das Programm “from scratch“ aufgebaut. Eine Übersicht der Systemarchitekur mit den verwendeten Komponenten ist in Abb. ... dargestellt. 16 KAPITEL 4. B-BAUM-TOOL 4.2.1 Server und Verzeichnisbaum Es wird ein gewöhnlicher HTTP-Server mit PHP aufgesetzt. Ein langjährig bewährter, und zugleich der meistgenutzte Webserver ist der frei erhältliche “Apache“ [Net16]. Hervorragende Tutorials zum Einrichten eines eigenen Servers sind auf der offiziellen Webseite 1 zu finden. Als serverseitige Programmiersprache wird PHP installiert, wodurch sich zwei sehr vorteilhafte Möglichkeiten ergeben. Zum einen können globale Einstellungen definiert werden, die alle Komponenten erhalten, welche an den Client geschickt werden. Und zum anderen können Daten, wie beispielhafte B-Bäume per AJAX nach Belieben nachgeladen werden, ohne den aktuellen Seitenstatus zu verändern. Details dazu sind in Abschnitt 4.3.1 ausführlich beschrieben. Der Verzeichnisbaum des B-Baum-Tools, und ein erstmaliger Aufruf ist in folgender Abbildung dargestellt: Dabei befinden sich in der config.php globale Einstellungsmöglichkeiten für den Administrator. Dieser kann in der Datei durch Werteveränderung das Aussehen und Verhalten des B-Baum-Tools nach Belieben anpassen. Beispielsweise kann er Limits für den Grad des Baumes, oder Schlüsselgröße angeben. Die grafische Darstellung wird durch Schriftart, Textgröße, Breite eines Schlüsseleintrags, uvm. verändert. Diese Variablen werden vor dem Versand zum Client durch PHP in den Quellcode von HTML, JavaScript, und CSS geschrieben. Die inhaltliche Gestaltung wird nach CSS-Standard in style.php definiert. Und das eigentliche Programm wird mit JavaScript realisiert, welches als jscript.php in das HTML-Dokument eingefügt ist. Für weitere Aufrufe während des Programmablaufs ist die Datei ajax.php zuständig, die, wie der Name bereits erahnen lässt, angefragte Daten an den Client retour schickt. 1 http://httpd.apache.org/ 17 KAPITEL 4. B-BAUM-TOOL 4.2.2 Der B-Baum in JavaScript Ursprünglich war JavaScript als Skriptsprache angedacht, mit deren Hilfe man schnell und einfach kleinere Programme erstellen konnte, die Browserinhalte manipulieren, und Benutzereingaben auswerten sollten. Es stellten sich aber bald weitreichendere Möglichkeiten wie beispielsweise objektorientierte Einsätze heraus. Dabei wird gänzlich auf Definitionen von Klassen verzichtet, stattdessen existieren in JavaScript Eigenschaften und Funktionen als Objekte. Diese können wiederum selbst Eigenschaften und Funktion beinhalten. Eigene Objekte können demnach als Funktionen definiert werden, wobei eine Instanz durch das key-word “new“ erzeugt wird. Auf Eigenschaften eines Objekt kann anschließend mit der Punkt-Notation zugegriffen werden. Nach diesem Prinzip wird nun ein Schlüsselelement des B-Baum erstellt: function key(value){ this.value = value; this.parent = null; this.left_key = null; this.right_key = null; this.left_child = null; this.right_child = null; } Mit Hilfe des Key-words this können Eigenschaften der eigenen Objektreferenz zugeordnet werden. Wird aus key eine neue Instanz erzeugt, behält diese den übergebenen Wert value. Alle weiteren Variablen stehen anfangs als Platzhalter für spätere Referenzen auf andere keys. Will man ein Schlüsselelement wie die Wurzel des B-Baums dauerhaft im Speicher halten, wird es einer Variable zugeordnet: var key_root = null; key_root = new key(1); console.log(key_root.value); // schreibt 1 zum Konsolen-Output Dabei erhält key root obige Eigenschaften und für value den Wert 1. Da für dieses Tool nicht mehrere B-Bäume gleichzeitig existieren, wird key root in globalem Scope angelegt, und bildet zugleich den Startpunkt für den B-Baum als mehrfach-verkettete Liste. So werden durch die insert-Funktion nach und nach seine Nachbarelemente und Kindsknoten aufgebaut. 4.2.3 Die grafische Darstellung Sobald ein B-Baum in JavaScript existiert, gibt es mehrere Möglichkeiten diesen im Browser grafisch auszugeben. Einerseits können mit dem HTMLElement “Canvas“ Pixelgrafiken erstellt werden. Allerdings müssen die18 KAPITEL 4. B-BAUM-TOOL se von JavaScript Bild für Bild neu gemalt werden. Am Beispiel des B-Baums wäre es folglich notwendig, Koordinaten und jegliche visuelle Veränderungen in JavaScript zusätzlich zu speichern. Dennoch ist diese Variante sehr schnell, da keine ständigen Zugriffe auf grafische HTML-Elemente wie bei SVG notwendig sind. Mit SVG können dem DOM vektorbasierende Grafiken hinzugefügt werden. Dabei wird das HTML-Dokument um XML-tags erweitert. Der Vorteil liegt hier in der Möglichkeit auf jedes Objekt direkt zugreifen zu können. Folgende kleine Gegenüberstellung vergleicht beide Varianten: Canvas - zeichnet eine Pixelgrafik - schnell bei komplexen Bildern - behält kein Wissen über Inhalt - Änderung erfordert neues Bild SVG - erstellt einzelne grafische Objekte - Zeit je nach Objektanzahl - Elemente bleiben erhalten - Manipulation in Element angeben An letztem Punkt ist erkennbar, dass Animationen und Transformationen in Canvas selbst in JavaScript umgesetzt werden müssen, wobei SVG-Elemente durch eine Zusatzangabe innerhalb des Objekts einfach manipuliert werden können. Aber den relevanten Unterschied, weshalb SVG für das B-Baum-Tool geeigneter erscheint, ist die Möglichkeit für jedes Element einen Event-Handler definieren zu können, wodurch beispielsweise ein Schlüsseleintrag per Mausklick für weitere Funktionalität direkt ausgewählt werden kann. Bei zunehmender Objektanzahl (bereits bei Ordnung 2, und Höhe 3) erweist sich ein ständiger Zugriff auf SVG-Objekte als nicht sehr praktikabel und langsam. Denn will man nach strukturellen Verschiebungen innerhalb des B-Baumes die aktuelle Position eines Objekts erhalten, muss man für alle darauf ausgeführte Transformationen dessen Koordinatenänderungen selbst berechnen. Um diesem Umstand entgegenzuwirken, gibt es in JavaScript Libraries, welche Objektpositionen behalten und updaten. Als einfacher erwies sich der Einsatz von DIV-Elementen, welche in einem Container innerhalb des HTML-Dokuments absolut positioniert werden. Dabei kann bei Zugriff die genaue Position abgefragt, und gesetzt werden kann. Eine kleine Hürde stellt allerdings die fehlende Möglichkeit dar, einfache grafische Elemente wie schräge Linien darzustellen, die beispielsweise Eltern- und Kindknoten miteinander verbinden. Mit folgender Funktion kann dieser Mangel behoben werden: function draw_line(x1,y1,x2,y2){ var length = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI; var transform = ’rotate(’+angle+’deg)’; 19 KAPITEL 4. B-BAUM-TOOL var top = 0; var left = 0; if (y2 < y1){ top = y2; left = x1; } else{ top = y1; left = x1; } ... var line = document.createElement("div"); line.style = "position: absolute; transform: "+transform+"; width: "+length+"px; left: "+left+"px; top: "+top+"px;"; document.getElementById("drawing").appendChild(line); } Dabei werden die Start-, und Ziel-Koordinaten der zu zeichnenden Linie benötigt, wodurch sich daraus die Länge, sowie der Neigungswinkel berechnen lassen. Zur gezielten absoluten Positionierung werden dann, der Linienorientierung entsprechend, die Offsets vom Container-Nullpunkt top und left bestimmt. So kann die Linie als neues DIV-Element erzeugt, und mit den berechneten Werten in den Container (hier als “drawing“ benannt) eingefügt werden. Wird nun eine Möglichkeit gefunden, einfache Transformationen und Animationen auf diese Elemente darzustellen, kann auch auf den Einsatz von SVG gänzlich verzichtet werden. 4.2.4 Transformationen und Animationen Die grafische Umsetzung der einzelnen Schlüssel könnte, wie folgt, aufgebaut werden: Dabei steht der Parameter id für den Schlüsseleintrag selbst, und x sowie y für dessen Koordinaten. Damit wird ein Rechteck kreiert, und dem bereits bekannten Container “drawing“ hinzugefügt. function create_rectangle(id,x,y){ var rect = document.createElement("div"); rect.id = id+"_rectangle"; rect.className = "rectangle"; rect.style = "position: absolute; left: "+x+"px; top: "+y+"px;"; rect.innerHTML = id; rect.onclick = function(){show_tooltip(this);}; document.getElementById("drawing").appendChild(rect); } Transformationen darauf wie Translationen (Objektverschiebungen) gestalten sich noch relativ einfach. Dazu werden die Offsets top und left 20 KAPITEL 4. B-BAUM-TOOL von einem Objekt abgefragt, und mit angepassten Werten wieder zugefügt: function move_object(id, x_offset, y_offset){ var element = document.getElementById(id); var x = element.offsetLeft; var y = element.offsetTop; element.style.left = (x + x_offset) + "px"; element.style.top = (y + y_offset) + "px"; } Schwieriger gestaltet es sich, solch eine Translation zu animieren. Von anderen Programmiersprachen ist bereits die sleep-Funktion bekannt. Damit ließe sich eine Verschiebung einfach durch eine Schleife durchführen, wo pro Schritt die Position verändert, und anschließend bis zum Folgeschritt eine Zeit lang “geschlafen“ wird. Genauer gesagt, wird dadurch die Programmausführung für eine bestimmte Zeit an andere Threads bzw. Prozesse abgegeben. In JavaScript gibt es eine solche Funktion nicht. Eine ähnliche Möglichkeit wäre der Einsatz des busy-waitingPatterns, wodurch der Prozess für eine bestimmte Zeit beschäftigt wird, bevor im Programmablauf (nächster Translationsschritt) weitergemacht wird. Das wäre aber nicht sehr benutzerfreundlich, da der Anwender während laufender Animationen keine Interaktionsmöglichkeit mehr hat. Ein weiterer Ansatz ist das Setzen von Timeouts (setTimeout und setInterval ), die nach Ablauf gewählter Zeitspannen eine bestimmte Funktion aufrufen. Solch eine Funktion könnte je einen Teilschritt für eine Objektverschiebung umsetzen. Man teilt dabei die Translation durch die gewünschte Dauer in Einzelschritte, und setzt diese dann in einer Schleife als Timeouts ab. Bis eine Timeout-Funktion aktiv wird, setzt das Programm seinen Ablauf fort. Problematisch wird diese Variante, sobald Objekte verschoben werden sollen, die voneinander abhängig sind. Beispielsweise ist bei Knotenüberläufen, und Knotenunterläufen eine rekursive Umstrukturierung von Teilbäumen möglich. Nur kann man bei deren Behandlungen nicht davon ausgehen, dass vorhergehende Verschiebungen bereits abgeschlossen sind. Man denke an einen Schlüssel, der in einen Knoten eingefügt werden soll, obwohl dieser möglicherweise noch verschoben wird. Hinzu kommt noch, dass populäre Browser eigene Rendering-Engines haben, welche Manipulationen auf HTML-Elemente in unvorhersehbaren zeitlichen Abständen behandeln. So kann es vorkommen, dass eine Schlüsselposition für eine Translation bestimmt wird, obwohl die Rendering-Engine die vorhergehende Verschiebung noch nicht durchgeführt hat. 21 KAPITEL 4. B-BAUM-TOOL Browserkompatibilität Web-Browser können auf grafische Inhalte sehr unterschiedlich reagieren. Alleine bei der Umsetzung von Transformationen zeigten sich große Unterschiede. Um diese Anwendung für gängige Browser kompatibel zu machen mussten ein paar Anpassungen vorgenommen werden. Für eine Rotation wurden beispielsweise diese Befehle zum CSS hinzugefügt. -moz-transform: rotate(30deg); -ms-transform: rotate(30deg); -o-transform: rotate(30deg); -webkit-transform: rotate(30deg); transform: rotate(30deg); Der eingesetzte Browser führt dabei den zuletzt erkannten Befehl aus, weshalb spezielle Befehle zuerst genannt werden. 4.3 Benutzerschnittstelle (GUI) Neben den Hauptoperationen für Bäume search, insert, und delete, denen bereits ein ausführliches eigenes Kapitel gewidmet wurde, werden hier noch weitere hilfreiche Funktionen beschrieben, welche den User in der Anwendung unterstützen. Generell wird großer Wert auf Benutzerfreundlichkeit, und im speziellen auf einfache und intuitive Bedienung gelegt. Dafür erhält auch jeder Schlüssel ein onclick-Event, welches direkt daneben ein kleines Popup öffnet, wo beispielsweise ein direktes Löschen dieses Schlüssels möglich ist (siehe 4.2.4, Seite 20). Hier ein kurzes, vereinfachtes Beispiel, wie solch ein Popup bzw. Tooltip erstellt werden kann: Der Übergabeparameter rect stellt das zugehörige Schlüsselelement dar. function show_tooltip(rect){ var x = rect.offsetLeft +rect_width; var y = rect.offsetTop - 20; var tooltip = document.createElement("div"); tooltip.className = "tooltip"; tooltip.style = "position: absolute; left: "+x+"px; top: "+y+"px;"; document.getElementById("drawing").appendChild(tooltip); // add div for closing on click var close = document.createElement("div"); close.className = "close"; close.style = "position: relative;"; close.innerHTML = "X"; close.onclick = function(){document.getElementById("drawing").removeChild(tooltip);}; 22 KAPITEL 4. B-BAUM-TOOL tooltip.appendChild(close); // add div for deletion var del = document.createElement("div"); del.className = "del"; del.style = "position: relative;"; del.innerHTML = "<img src=’./img/delete.png’ onclick=’delete(rect.innerHTML);’ style=’width:30px;padding:5px;’> L&ouml;schen !"; tooltip.appendChild(del); } Der Tooltip als Popup bekommt in diesem Beispiel zwei Kindelemente zu seinem Strukturbaum dazu. Das Div-Element close erhält die Referenz des gerade erstellten Tooltips, wodurch dieses bei Klick entfernt werden kann. Das Div-Element del hingegen, führt bei Klick die Löschoperation für diesen Schlüssel aus. Als weiteres Beispiel werden Hover-Effekte eingesetzt, sobald sich der Fokus auf einem Element des B-Baums befindet, und zudem auch HighlightEffekte bei Animationen verwendet. Diese werden von verschiedenen Abschnitten der Baumoperationen aufgerufen, und setzen dabei einen Timeout ab: function highlight_rectangle(k){ var rectangle = document.getElementById(k.value+"_rectangle"); setTimeout(function(){rectangle.style.backgroundColor = "snow";}, 200); } 4.3.1 Laden von Beispielbäumen Mit PHP als serverseitige Programmiersprache ist es für den Client möglich, zum aktuellen Seitenstatus gewisse Daten nachzufordern, und per JavaScript einzubinden. Damit können beispielhafte B-Bäume nach Belieben in das Tool geladen werden. Es wird dabei von der AJAXTechnologie Gebrauch gemacht, wobei die Datenübertragung vereinfacht mit JSON-Objekte realisiert wird. Über eine Schleife in index.php werden alle Beispielbäume aus dem Verzeichnis tree examples ausgelesen, und einem Auswahlmenü als Optionen hinzugefügt. <?php $tree_array = scandir("./tree_examples/"); $tree_array = array_diff($tree_array,array("..",".")); ?> <div id="div_example_tree"> Beispielbaum laden <select id="tree_examples" onchange="tree_example_load();"> 23 KAPITEL 4. B-BAUM-TOOL <option disabled selected>Beispielb&aumlume</option> <?php foreach($tree_array as $tree){ echo "<option>".$tree."</option>"; } ?> </select> </div> Wählt man eine Option aus, wird tree example load() ausgeführt. Die Abarbeitung kann in drei Teile zusammengefasst werden. Zuerst wird der ausgewählte Baum per AJAX ins Programm geladen. Das dadurch erhaltene serialisierte JSON-Objekt, wird dann in ein mehrdimensionales Array gespeichert. Mit einer verschachtelten Schleife kann dann jedes Element als neuer key dem B-Baum in JavaScript zugeführt werden. Zur grafischen Ausgabe wird anschließend jede Höhe, beginnend von den Blättern, zentriert, und mittig übereinander angeordnet. Zur vereinfachten Darstellung werden hier manche Abschnitte im Code-Auszug in sehr reduziertem Pseudocode angeführt: function tree_example_load(){ ... var select = document.getElementById("tree_examples"); var option = select.options[select.selectedIndex].value; var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST","ajax.php",false); xmlhttp.send("tree_example="+option); var tree = JSON.parse(xmlhttp.responseText); ... ... for(i=0; i< tree.length ;i++){ for(x=0; x< tree[i].length ;x++){ for(y=0; y< tree[i][x].length ;y++){ insert_key(tree[i][x][y]); draw_key(tree[i][x][y]); } } } ... ... var leaf_left = leftest_key(); var leaf_right = rightest_key(); var center_point = (document.getElementById(leaf_left.value+"_rectangle").offsetLeft + document.getElementById(leaf_right.value+"_rectangle").offsetLeft) /2; for(i=0; i< tree.length;i++){ 24 KAPITEL 4. B-BAUM-TOOL var last_x_index = tree[i].length-1; var last_y_index = tree[i][last_x_index].length-1; var parent_center_point = (document.getElementById(tree[i][0][0]+"_rectangle").offsetLeft + document.getElementById(tree[i][last_x_index][last_y_index]+ "_rectangle").offsetLeft) /2 var offset_x = center_point - parent_center_point; for(x=0; x< tree[i].length ;x++){ for(y=0; y< tree[i][x].length ;y++){ var element_offset = offset_x + document.getElementById(tree[i][x][y]+"_rectangle").offsetLeft; rectangle_move(parseInt(tree[i][x][y]), element_offset); } } } ... } Die Indizes im B-Baum-Array tree[i ][x ][y] stehen für: i als jeweilige Höhe, x als Knoten einer Höhe, und y als einzelne keys. Damit die Beispielbäume vom Programm fehlerfrei geladen werden können, müssen sie gewisse Kriterien erfüllen. Genauer gesagt, wird ein spezielles Format vereinbart, indem einzelne Bäume als Dateien vorliegen sollen. Dazu gibt folgender Eintrag in der Datei README.txt auskunft: every file in the directory "tree_examples" holds an b-tree. the file needs to be built with following rules: first line has number n (minimum number of elements in node). every other line contains keys of same tree-height. lines have order from root to leafs. separator in node is ",". separator between nodes is "+". an example: n=1 (binary-tree) 1 8,16 4+12+19,33 1,2+6+10+14+18+20+44 4.3.2 Erstellen eines neuen Baumes Hier hat ein User die Möglichkeit die Ordnung des gewünschten Baumes in einem Auswahlfeld zu wählen. Daraufhin wird er zur Eingabe des ersten Schlüssels (Wurzel) aufgefordert, mit dem der Baum in JavaScript 25 KAPITEL 4. B-BAUM-TOOL initialisiert wird. Die Datei index.php stellt die möglichen Ordnungszahlen nach der Limitation des Administrators als Optionen dar: <div id="div_new_tree"> Neuen B-Baum der Ordnung <select id="select_min_keys" onchange="tree_build()"> <option disabled selected>n</option> <?php for($i=1; $i<=$n_limit; $i++){ echo "<option>".$i."</option>"; } ?> </select> erstellen </div> Bei Auswahl einer Option wird tree build() ausgeführt. Diese Funktion fragt den Benutzer nach dem ersten Schlüssel, mit dem der B-Baum begonnen werden soll. Mit diesem Wurzelelement wird die verkettete Liste des B-Baumes begonnen, und anschließend grafisch erstellt. function tree_build(){ var value = prompt("Mit welchem Schl&uuml;ssel wollen Sie den B-Baum beginnen?"); if(!check_input_number(value)){ return 0; } var select = document.getElementById("select_min_keys"); n = select.options[select.selectedIndex].value; select.selectedIndex = 0; document.getElementById("drawing_title").innerHTML = "B-Baum der Ordnung "+n; document.getElementById("drawing").innerHTML=""; key_root = new key(value); create_rectangle(value,svg_width/2,rect_width*2); } Durch check input number() wird der einzufügende Schlüssel dahingehend überprüft, ob er einem gültigen Wert entspricht. Ist dies nicht der Fall, wird dem Anwender eine entsprechende Meldung angezeigt, und die fehlerhafte Eingabe entfernt. function check_input_number(value){ if(value > max_input_number){ status_write("Es sind nur Zahlen bis "+max_input_number+" erlaubt. "); 26 KAPITEL 4. B-BAUM-TOOL document.getElementById("input_key").value = ""; return false; } else if(isNaN(value)){ status_write(value+" ist keine Zahl. "); document.getElementById("input_key").value = ""; return false; } else if(value < 0){ status_write("Bitte einen positiven Wert eingeben!"); document.getElementById("input_key").value = ""; return false; } return true; } 27 Kapitel 5 Auswertung und Ausblick Im direkten Vergleich mit Canvas und SVG wurden bereits einige Vorteile für den bevorzugten Einsatz mit SVG hervorgehoben. In weiterer Gegenüberstellung zeigte sich, dass alle benötigten Grafiken, Transformationen, und Animationen auch mit Hilfe von Div-Elementen umgesetzt werden können. Dazu benötigte es nur ein paar kleine Tricks, und Anpassungen. Und in Folge ergaben sich sogar weitere Vorteile. Bei SVG ist der Schlüsseleintrag zwingend ein eigenständiges Textelement. Wird der umschließende Container (grafische Darstellung des Schlüssels als Rechteck) bewegt, muss zusätzlich die selbe Operation auf das Textelement ausgeführt werden. Mit Div-Containern hingegen kann der Schlüsselwert als darin stehender Text (innerHTML) eingebunden werden, wodurch keine weitere Verschiebung notwendig wird. In dieser Arbeit wurde besonders Wert darauf gelegt, dass ein qualitatives Tool entsteht, ohne es mit fremden Code überladen zu müssen. Es seien aber durchaus Bibliotheken und Frameworks zu erwähnen, die einem Programmierer die Arbeit sehr erleichtern können, und zudem auch visuell ansprechend sind. Als Hilfe könnte man beispielsweise das bekannte Framework “Bootstrap“ einsetzen, welches hauptsächlich Gestaltungsvorlagen für die Benutzeroberfläche liefert. Speziell für grafische Strukturen eignet sich die JavaScipt-Bibliothek “D3.js“, welches die Schnittstelle zum DOM stellt. So lassen sich Daten in JavaScript eindrucksvoll in grafische Bäume verwandeln. Als Erweiterung zum B-Baum-Tool könnte man die Funktionalität hinzufügen, einen neu erstellten Baum speichern zu können. Dieser würde nach den Vorgaben , wie in 4.3.1 beschrieben, zu den Beispielbäumen hinzugefügt werden. Sollte dies nur für einen Administrator möglich sein, wäre auch eine zusätzliche Authentifizierung notwendig. 29 Glossar Technologien Beschreibung AJAX Asynchronous JavaScript and XML Datenübertragung zwischen Browser und Server ohne Page-Reload. Canvas Englisch für “Leinwand“. Ein HTML-Element. Aus JavaScript erstellte Pixelgrafik. CSS Cascading Style Sheets Gestaltung der Elemente des HTML-Dokuments. DOM Document Object Model Schnittstelle für Zugriff auf Knoten des HTML-Strukturbaumes. HTML Hypertext Markup Language Textbasierte Auszeichnungssprache zur Strukturierung. JavaScript Ursprünglich LiveScript bei Netscape Navigator Clientbasierte (hauptsächlich) Skriptsprache. Behandelt DOM-Manipulationen, AJAX, User-Interaktionen, etc. JSON JavaScript Object Notation Textbasiertes Format zur Übertragung von Daten. Serialisierung von Objekten möglich. PHP PHP Hypertext Preprocessor Serverseitige Programmiersprache. SVG Scalable Vector Graphics Grafiken, die sich aus primitiven geometrischen Formen aufbaut. 30 Literaturverzeichnis [Bay72] R. Bayer: Symmetric binary B-Trees: Data structure and maintenance algorithms, Acta Informatica, volume 1(4), (1972), pages 290–306, URL http://dx.doi.org/10.1007/ BF00289509. [BZ13] K. Bauknecht and C. Zehnder: Grundlagen für den Informatikeinsatz, XLeitfäden der Informatik, Vieweg+Teubner Verlag, 2013, URL https://books.google. at/books?id=ICPwBgAAQBAJ. [Com79] D. Comer: Ubiquitous B-Tree, ACM Comput. Surv., volume 11(2), (1979), pages 121–137, URL http://doi.acm.org/ 10.1145/356770.356776. [KE09] A. Kemper and A. Eickler: Datenbanksysteme: eine Einführung, Oldenbourg, 2009, URL https://books. google.at/books?id=\_lgBQAAACAAJ. [Net16] Netcraft: Marktanteile Webserver, Abgerufen am 10.05.2016, URL https://news.netcraft.com/archives/category/ web-server-survey/. [SA16] Statistik-Austria: Einwohnerzahl Österreichs, Abgerufen am 21.09.2016, URL http://www.statistik-austria.at/. [Sch13] M. Schneider: Implementierungskonzepte für Datenbanksysteme, Springer Berlin Heidelberg, 2013, URL https://books.google.at/books?id=DYLyBQAAQBAJ. 31