Natix – ein natives XML-DBMS Thorsten Fiebig, Carl-Christian Kanne, Guido Moerkotte Natix – ein natives XML-DBMS Die rapide Zunahme an XML-Dokumenten verlangt nach einer systematischen Verwaltung von XML-Dokument-Kollektionen. Das in diesem Aufsatz beschriebene Datenbankmanagementsystem Natix ist speziell für die effiziente Verwaltung von XML-Dokumenten entwickelt worden. Wir beschreiben die Architektur von Natix und ausgewählte Module für die Speicherung und Anfrageauswertung. 1 Einleitung Dieser Artikel beschreibt das native XML-Repository Natix, das speziell für die Verwaltung von XML-Dokumenten entwickelt wurde. Wozu Natix? Durch die rasant wachsende Akzeptanz von XML [XML] gibt es mehr und mehr XML-Dokumente, die systematisch verwaltet werden müssen. Ein System, das dies unterstützt, sollte dabei mindestens folgende Anforderungen erfüllen: Es muss XML-Dokumente effektiv speichern können und den effizienten Zugriff auf ganze XML-Dokumente oder Teile davon erlauben. Um sicheres Arbeiten mit Dokumentkollektionen zu gewährleisten, muss ein solches System eine Transaktionsverwaltung beinhalten, die Recovery und Synchronisation realisiert. Vom W3C standardisierte deklarative Anfragemechanismen wie X-Path [XPath] und XQuery [XQuery] sollten selbstverständlich ebenfalls unterstützt werden. Zur Realisierung von Anwendungen auf einem solchen System ist die Unterstützung von DOM [DOM] und SAX [SAX] unabdingbar. Traditionell werden Datenbankmanagementsysteme (DBMS) für die Verwaltung großer Datenmengen eingesetzt. Es liegt daher zunächst einmal nahe, auch für die systematische Verwaltung von XML-Dokumenten ein (objekt-)relationales DBMS (RDBMS) oder ein objektorientiertes DBMS (OODBMS) einzusetzen. Der nächste Abschnitt beschreibt einige Nachteile, die aus der Verwendung eines RDBMS entstehen. Nur kurz wird auf die analogen Nachteile bei der Verwendung eines OODBMS eingegangen. Ein alternativer Ansatz ist die Verwen- Datenbank-Spektrum 1/2001 dung eines Datenbanksystems, das speziell für XML entwickelt wurde. Ein solches System ist Natix, dessen Architektur in Abschnitt 3 beschrieben wird. Die darauf folgenden Abschnitte beschreiben das Speichersubsystem und die Anfrageauswertungsmaschinerie. Der letzte Abschnitt fasst den Artikel zusammen. 2 Speicherung von XMLDokumenten in einem RDBMS Zur Speicherung von XML-Dokumenten in relationalen Datenbanksystemen gibt es viele verschiedene Ansätze [FlKo99, KlMe00,ScKeWiWa00,ShGaTuYhDeNa 99,SuRiLo00,YoAmShUe01]. Der Bereich der möglichen Speicherungsformen von XML-Dokumenten in relationalen Datenbanksystemen wird abgesteckt durch die Speicherung von ganzen XML-Dokumenten als große Zeichenfelder, auch CLOB (character large object) genannt, auf der einen Seite und der Speicherung einzelner Dokumentknoten in einzelnen Tupeln auf der anderen Seite. Vielfältige Zwischenformen sind möglich. Der einfachste Ansatz speichert jedes Dokument in einem CLOB. Wie Abbildung 1 zeigt, unterscheidet sich dieser Ansatz in den Auswirkungen nicht wesentlich von der Situation, die entsteht, XML−Editor XSL−Prozessor wenn man direkt ein Dateisystem verwendet. Man hat jedoch den Vorteil des Transaktionsmanagements. Will man ein ganzes Dokument exportieren, so geht dies relativ schnell. Zu aufwendig ist es hingegen, gezielt ein Fragment eines Dokuments zu exportieren. Hierzu muss der gesamte CLOB ausgelesen und geparsed werden, bevor das zu exportierende Fragment bestimmt werden kann. Falls das RDBMS weitere Werkzeuge wie Parser, XPath-Prozessor und XQuery-Prozessor integriert, entfällt zumindest deren getrennte Verwaltung. Intern im RDBMS wird aber immer noch jedes in einem CLOB gespeicherte Dokument vor jeder Verarbeitung zerteilt. Der hierfür zuständige Parser kann dann eine DOM- oder SAX-Schnittstelle zur Verfügung stellen, auf der auch andere Anwendungen arbeiten können. Dies führt zu entsprechenden Leistungsverlusten. Will man nun XPath-Ausdrücke oder XQuery-Anfragen auf den in CLOBs gespeicherten XML-Dokumenten auswerten, so müssen die Dokumente aus den CLOBs gelesen, geparsed und dann der Ausführungsmaschinerie zugeführt werden. Es ist nicht offensichtlich, wie diese Ausführungsmaschinerie mit derjenigen für die Bearbeitung von SQL-Anfragen zusammengeführt werden kann bzw. Teile davon wiederverwendet werden können. Insgesamt betrachtet birgt die Verwendung von CLOBs erhebliche Ineffizienzen. XPath−Prozessor XQuery−Prozessor Parser RDBMS Dok ... Dok Index Abb. 1: Anwendungen mir RDBMS, Dokumente als CLOB 5 Natix – ein natives XML-DBMS Die Situation ändert sich, wenn man die einzelnen Bestandteile eines XMLDokuments in Tupeln speichert (siehe Abbildung 2). Hier ergeben sich viele verschiedene Alternativen, die zum großen Teil in den oben zitierten Aufsätzen beschrieben werden. Zur Veranschaulichung der Nachteile dieses Ansatzes beschränken wir uns auf eine sehr einfache und generische Abbildung von XML-Dokumenten auf Tupel. Dazu betrachten wir die beiden folgenden Beispieldokumente: <books> <book> <author>D. Maier </author> <title>The Theory of Relational Databases </title> </book> <book> <author>D. Loveland </author> <title>Automated Theorem Proving: A Logical Basis </title> </book> </books> <articles> <article> <author>E. Codd </author> <title>A Relational Model of Data for Large Shared Data Banks </title> </article> <article> <author>J. Corbin </author> <author>M. Bidoit </author> <title>A Rehabilitation of Robinsons’s Unification Algorithm </title> </article> </articles> Als Grundlage für die Verteilung eines XML-Dokuments auf einzelne Tupel dient die Darstellung eines XML-Dokuments als Baum. Für das erste Beispieldokument findet sich eine solche Baumdarstellung in Abb. 3. Jeder Knoten des XML-Baums wird nun als ein Tupel gespeichert (siehe Abbildung 4). Dabei speichern wir für jeden Knoten den Identifikator des Knotens id/. Die Kindknoten werden durchnumeriert, um ihre Ordnung zu registrieren. Hierzu dient das Attribut nummer/. Das Attribut vater/ be- 6 XML−Editor XSL−Prozessor load/dump XPath−Prozessor DOM/SAX XQuery−Prozessor Uebersetzer RDBMS ... Abb. 2: Anwendungen mit RDBMS, Dokumentknoten als Tupel books book author book title D. Maier author title D. Loveland The Theory of Relational Databases Automated Theorem Proving: A Logical Basis Abb. 3: Ein Dokument als Baum inhaltet den Identifikator eines Vaterknotens. Es ist für Wurzelknoten auf NULL gesetzt. Falls es sich um einen Elementknoten handelt, so wird der Elementname im Attribut name/ verzeichnet. Falls es sich um einen Textknoten handelt, so beinhaltet das Attribut text/ den Inhalt des Textknotens. Man beachte, dass diese Abbildung unvollständig ist. Beispielsweise werden keine Attributknoten behandelt. Des weiteren fehlt die Behandlung der verschiedenen Entitytypen, Processing-Instructions, Comment-Knoten usw. Eine vollständige Abbildung ist alles andere als trivial und würde an dieser Stelle zu weit führen. Wir betrachten statt dessen wieder, wie Anwendungen mit einer solchen Datenbank arbeiten können. Zunächst stellen wir fest, dass das Exportieren eines gesamten Dokuments ein aufwendiges Unterfangen ist, da alle Knoten des Dokuments zusammengesucht werden müssen. Das Exportieren eines kleinen Dokumentfragmentes, zum Beispiel des Inhalts eines Textknotens hingegen geht bei gegebenem Knotenidentifikator recht schnell. Um weitergehende Anwendungen auf der Datenbank realisieren zu können, benötigt man wieder eine DOM- oder SAX-Schnittstelle. Bei der Speicherung von XML-Dokumentknoten in einzelnen Tupeln scheidet die Verwendung eines Parsers aus. Auf der anderen Seite können aber die Navigationsoperationen (andere selbstverständlich auch) mittels SQL nachgebildet werden. Den nächsten Geschwisterknoten findet die folgende SQL-Anfrage: Datenbank-Spektrum 1/2001 Natix – ein natives XML-DBMS Dokumentknoten id n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 nummer 1 1 1 1 2 1 1 1 1 2 1 vater NULL n1 n2 n3 n2 n5 n1 n7 n8 n7 n10 name books book author NULL title NULL book author NULL title NULL n20 n21 n22 n23 n24 n25 1 1 1 1 2 1 NULL n20 n21 n22 n21 n24 articles article author NULL title NULL n26 n27 n28 n29 n30 n31 n32 1 1 1 1 1 3 1 n20 n26 n27 n26 n29 n26 n31 article author NULL author NULL title NULL text NULL NULL NULL »D. Maier« NULL »The Theory of Relational Databases« NULL NULL »D. Loveland« NULL »Automated Theorem Proving: A Logical Basis« NULL NULL NULL »E. Codd« NULL »A Relational Model of Data for Large Shared Data Banks« NULL NULL »J. Corbin« NULL »M. Bidoit« NULL »A Rehabilitation of Robinsons’s Unification Algorithm« Abb. 4: Zwei Dokumente auf Relationen verteilt select y.id from Dokumentknoten x, Dokumentknoten y where x.id = :id and x.vater = y.vater and x.nummer+1 = y.nummer Man beachte den Aufwandsunterschied zwischen dieser Anfrage und der einfachen Dereferenzierung eines Zeigers. Wenn man sich jetzt kompliziertere DOM-Funktionen vorstellt, wie beispielsweise das Auffinden aller direkten und indirekten Nachfolgerknoten eines gegebenen Knotens, wird sehr schnell deutlich, wie aufwendig solche DOMOperationen nachgebildet werden müssen. Im betrachteten Fall müsste sogar eine rekursive Anfrage abgesetzt werden. Bei der Verwendung von Anwendungen wie XPath-Auswertern und XQueryAuswertern hat man jetzt zwei Möglichkeiten. Zum einen können diese wiederum auf eine DOM-Schnittstelle aufsetzen. Es sollte allerdings offensichtlich sein, dass sich dieses nach den vorherigen Betrachtungen aus Leistungsgesichtspunkten heraus verbietet. Die andere Möglichkeit besteht darin, XPath-Aus- Datenbank-Spektrum 1/2001 drücke und XQuery-Ausdrücke in SQLAnfragen zu übersetzen. Hier ergeben sich drei Probleme. Zum einen bedeutet diese zusätzliche Abbildungsschicht von XPath bzw. XQuery nach SQL und für das Ergebnis von Relationen zu XMLFragmenten/Knotenmengen einen Leistungsverlust. Zum zweiten ist es nicht möglich, alle XPath- oder XQuery-Ausdrücke in SQL zu übersetzen. Hierzu ist SQL nicht mächtig genug. Zum dritten sind die erzeugten SQL-Anfragen ähnlich ineffizient, wie für die DOM-Operationen demonstriert. Beispielsweise findet der simpelste XPath-Ausdruck »//« alle direkten und indirekten Nachfolgerknoten eines gegebenen Knotens. Man kann sich also leicht vorstellen, wie aufwendig die Berechnung allgemeiner XPath-Ausdrücke wird. Von XQuery-Anfragen wollen wir hier lieber schweigen. Statt dessen wenden wir uns noch einem weiteren Problem zu. Speichert man Knoten verschiedener XML-Dokumente in einer Relation – und es ist davon auszugehen, dass man nicht für jedes Dokument neue Relationen anlegt, so hat man bei der Synchronisation verschiedener Anwendungen folgendes Problem. Um Phantomprobleme zu vermeiden, also Knoten, die während der Bearbeitung mal sichtbar sind und mal nicht, muss in einem RDBMS immer die ganze Relation gesperrt werden, in der ein Tupel (Knoten) eingefügt wurde. Dies kann leicht dazu führen, dass mehrere Dokumente in Gänze gesperrt werden, obwohl eine Transaktion vielleicht nur in einem Dokument einen Knoten einfügt. Dies ist eine oft unerträgliche Situation. An dieser Stelle sei kurz angemerkt, dass die Verwendung eines OODBMS ähnliche Nachteile birgt, wie die Verwendung eines RDBMS bei Speicherung von Dokumentknoten in einzelnen Tupeln. Lediglich die Operationen der DOMSchnittstelle können effizienter implementiert werden. Aber nicht nur aus technischer, sondern auch aus betriebswirtschaftlicher Sicht ergeben sich einige Nachteile durch die Verwendung eines RDBMS zur Speicherung von XML-Dokumenten. Relationale Datenbankmanagementsysteme sind oftmals relativ alte, über Jahre und Jahrzehnte gewachsene Systeme, die für vielfältige Anwendungsbereiche mehrfach erweitert wurden. Daraus ergibt sich, dass es sich um relativ komplexe, schwierig zu installierende und administrierende Systeme handelt. Durch die notwendigen XML-spezifischen Erweiterungen verbessert sich diese Situation nicht. Verwendet man nun ein relationales DBMS nur für die Speicherung von XML-Dokumenten, so bezahlt man nicht nur Lizenzgebühren für viele Codezeilen, die man nie ausführen wird, man handelt sich auch den hohen Installations- und Administrationsaufwand ein. Vorteilhaft bei der Verwendung eines RDBMS ist, dass oft bereits geschultes Personal in den Unternehmen vorhanden ist. Ausserdem sind die RDBMS-Hersteller bemüht, die Administration ihrer Systeme zu vereinfachen. 3 Natix-Systemüberblick Bei der Realisierung von Natix wurde darauf Wert gelegt, die oben geschilderten Probleme beim Einsatz von konventionellen DBMS zur Speicherung von XML an der Wurzel zu beheben. Durch die Berücksichtigung der XML-Anforderungen bei Entwurf und Implementierung auch der unteren Schichten des Systems 7 Natix – ein natives XML-DBMS wurde dabei ein sehr leistungsstarkes, auf XML spezialisiertes DBMS geschaffen. Natix ist in C++ auf UNIX-Plattformen entwickelt, Windows-Versionen und Java-Anbindungen sind aber in der Erprobung. Die Architektur von Natix besteht aus drei Ebenen (Abbildung 4). Die unterste ist die Speicherebene, die für die Speicherung von XML-Daten, Metadaten und Indexstrukturen zuständig ist. In der nächsthöheren Ebene befinden sich die verschiedenen Datenbankdienste, die die über einfache Speicherung hinausgehenden Anforderungen der Anwendungen erfüllen. Speicherebene und Dienste bilden zusammen die Natix Engine. Die Dienste kommunizieren untereinander und mit den Anwendungen durch das Natix Engine Interface, das eine einheitliche Schnittstelle für die gesamte DatenbankEngine zur Verfügung stellt. Auf Basis des Natix Engine Interface sind dann in der Anbindungsebene die verschiedenen Anwendungsanbindungen realisiert, in der die internen Repräsentationen von Dokumenten, Anfragen und Metadaten in die vom jeweiligen API benötigte Darstellung umgewandelt werden. 3.1 Speicherebene Dieser Teil von Natix übernimmt die Verwaltung aller persistenten Daten. Dazu gehören neben den XML-Dokumenten, auf deren Speicherung in Abschnitt 4 im Detail eingegangen wird, Indexstrukturen, Metainformationen und Protokolle für die Recovery-Algorithmen der Transaktionsverwaltung. Die Speicherungsschicht enthält neben einem Cache-Mechanismus eine Abstraktionsschicht für Massenspeichergeräte, so dass beliebige Medien mit blockweisem, wahlfreiem (Random Access) Zugriff als Träger von Natix-Partitionen dienen können (neben normalen Dateien kann Natix so auch direkt auf Festplattenpartitionen zugreifen). Neben Standard-Indexstrukturen wie B-Bäumen und invertierten Listen ist auf dieser Ebene auch ein Index geplant, der in der Lage ist, neben der absoluten Positionen von Suchbegriffen auch Zusatzinformationen über den Kontext zu liefern, in dem der Begriff vorkommt [FiMo00]. 3.2 Datenbankdienste Das Natix Engine Interface stellt ein Framework zur Kommunikation der Dienste zur Verfügung. Operationen wie Compilation (Prepare) und Auswertung einer Anfrage, der Import und Export von Dokumenten werden als Request an das Engine Interface gestellt und an die jeweils beteiligten Dienste weitergeleitet. Die virtuelle Maschine dient der Auswertung von Anfragen. Zur effizienten Abarbeitung simuliert sie einen Prozessor, dessen Befehlssatz neben einfachen Operationen auf Basistypen auch mächtige Befehle zum Zugriff auf Dokumente Anwendung Anbindungsebene C++ DOM Treiber Java DOM Treiber SAX Treiber Dateisystem− Treiber Natix Engine Interface Datenbankdienste Speicherungsebene Query Compiler Natix Virtual Machine Transaktions− verwaltung Speicherung Natix Engine Abb. 5: Architekturüberblick 8 Objekt− manager enthält. Dabei kann die virtuelle Maschine bei der Auswertung der Anfragen direkt auf die Hintergrundspeicherrepräsentation der XML-Dokumente zugreifen, ohne diese zunächst mit hohem CPUAufwand in eine Hauptspeicherrepräsentation (z.B. einen DOM-Tree) umzuwandeln. Auf die Struktur der Auswertungsprogramme wird in Abschnitt 5 ausführlicher eingegangen. Der Query Compiler übernimmt die Aufgabe, die in XML-Anfragesprachen formulierten Anfragen in Programme für die Natix Virtual Machine zu übersetzen. Es können auch mehrere Query Compiler im System vorhanden sein, falls mehrere Anfragesprachen unterstützt werden. Derzeit steht ein XPath-Compiler zur Verfügung. Näheres zur Anfragebearbeitung folgt in Abschnitt 5. Die Transaktionsverwaltung stellt die Infrastruktur für Mehrbenutzerbetrieb zur Verfügung, bei dem die ACID-Eigenschaften (Atomicity, Consistency, Isolation, Durability) für die parallel ablaufenden Transaktionen garantiert werden können. Die wesentlichen Komponenten sind hier erstens die Isolation der Transaktionen durch das Verwalten von Sperren auf Objekten (wie Dokumenten und Knoten), sowie zweitens die Recovery, die für die Wiederherstellung der Daten bei einem Systemausfall oder dem Abbruch einer Transaktion zuständig ist und dafür eine Logdatei mit den erfolgten Änderungsoperationen verwaltet. Dabei verlangt das Anforderungsprofil eines XML-DBMS mit sehr vielen Teilobjekten pro Dokument auch spezielle Sperrtypen und Protokolleinträge für Dokumente und Teildokumente. Eine konventionelle Transaktionskomponente ist hier schnell an der Grenze ihrer Leistungsfähigkeit. In Abschnitt 4.4 gehen wir beispielhaft auf die Optimierungsmöglichkeiten in der Isolationskomponente ein. Um korrekten und durchsatzstarken Mehrbenutzerbetrieb zu ermöglichen, ist die Transaktionsverwaltung dabei eng mit der Speicherebene und der Anfragebearbeitung verzahnt, damit Sperren und Logeinträge für XML-Daten mit minimalem Overhead verwaltet werden können. Zur Vermeidung von wiederholten Repräsentationswechseln zwischen der Hintergrundspeicherrepräsentation und den verschiedenen, von den Anwendungen verwendeten Hauptspeicherrepräsen- Datenbank-Spektrum 1/2001 Natix – ein natives XML-DBMS tationen (z.B. DOM-Tree) von Dokumenten wird ein Objekt-Cache eigesetzt, auf den die verschiedenen Anwendungstreiber über einen Objektmanager zugreifen können. 3.3 Anbindungsebene In der Anbindungsebene sind die Schnittstellen zum Zugriff auf die DatenbankEngine aus den verschiedenen Anwendungen realisiert. Neben den obligatorischen DOMSchnittstellen für C++ und Java ist hier auch ein Dateisystemtreiber angesiedelt, der den Datenbankinhalt allen Anwendungen zur Verfügung stellt, die mit regulären Dateien arbeiten können. Dadurch kann die eventuell bestehende anfängliche Hürde beim Einsatz eines neuen DBMS leichter genommen werden. 4 Speicherung 4.1 Anforderungen In der Regel wird auf XML-Dokumente in Programmen mit Interfaces wie DOM oder SAX zugegriffen, in denen die Dokumentstruktur als Baum abgebildet wird. Ein geeignetes Speicherungsformat für XML-Dokumente in einem DBMS muss die in der Einleitung angedeuteten Anforderungen erfüllen: 1. Navigation durch die Baumstruktur muss ohne erneuten Parsingaufwand möglich sein. 2. Man muss Dokumente mit beliebiger (auch ohne) DTD speichern können, und DTDs müssen entsprechend einem DB-Schema dem System zunächst bekannt gemacht werden. 3. Typische Zugriffsmuster (z.B. Navigation entlang der XPath-Achsen, Export einer textuellen XML-Darstellung) müssen effizient unterstützt werden. Die typischerweise verwendeten generischen Formate zur Speicherung von XML-Dokumenten genügen den Anforderungen nicht: Bei der Speicherung von ganzen Dokumenten in CLOBs geht die Dokumentstruktur verloren, und die Navigation zwischen einzelnen Dokumentknoten kann nicht effizient unterstützt werden, sondern erfordert erneutes Parsen und damit in der Regel aufwendige I/O-Zugriffe auch auf unbeteiligte Dokumentbestandteile. Speichert man Dokumente knotenweise in einem herkömmlichen DBMS, Datenbank-Spektrum 1/2001 Abb. 6: In Teilbäume zerlegtes Dokument geht sehr viel Platz verloren, da jeder Knoten zusätzlich zum Knotentyp (inkl. Tag-Namen) noch Referenzen auf den Vater-, Geschwister- und Kinderknoten enthalten muss. Diese Referenzen, z.B. als Fremdschlüssel realisiert, müssen beliebige andere Knoten erreichen können und dominieren daher den Platzaufwand. Außerdem sind die Knoten eines Dokuments über den Hintergrundspeicher verteilt und müssen wiederum durch aufwendige I/O-Zugriffe beschafft werden. Natix verwendet ein hybrides Speicherungsformat, das Teilbäume eines Dokuments jeweils auf einer Hintergrundspeicherseite clustert und dort in einem kompakten Format ablegt (Abbildung 6). Passt ein Teilbaum aufgrund einer Änderungsoperation nicht mehr auf eine Seite, wird er gesplittet und auf mehrere neue Seiten verteilt. Nur für Referenzen, die Seitengrenzen überschreiten, muss ein platzaufwendigeres Format verwendet werden. Im Folgenden wird nun zunächst das Speicherungsformat der Teilbäume auf den Seiten beschrieben und dann die Verteilung von größeren Dokumenten auf mehrere Seiten skizziert. 4.2 Speicherungsformat auf den Seiten Der Hintergrundspeicher in Natix wird in Blöcken oder Seiten von fixer Länge (max. 64K) eingeteilt. Auf jeder Hintergrundspeicherseite können mehrere Teilbäume (also auch mehrere Dokumente pro Seite) abgelegt werden, wobei jeder Teilbaum von der unter der XML-Spei- cherung befindlichen Ebene als opaker, variabel großer Datensatz gehandhabt wird. Zur Verwaltung dieser Datensätze kommen erprobte Techniken wie Slotted Pages und extentbasiertes Freispeichermanagement zum Einsatz. Jeder Teilbaum-Datensatz besteht aus einem Header und den Knotendaten. Der Header enthält eine Referenz auf den Vaterteilbaum sowie eine Kennung, zu welchem Dokument er gehört. Die Knoteninformationen bestehen ebenfalls jeweils aus einem Header und dem Knoteninhalt. Der Knoteninhalt kann dabei entweder (z.B. bei Text- oder Attributknoten) ein Stringwert oder (z.B. bei Elementknoten) eine Folge von Kinderknoten sein. Der Knotenheader enthält den Knotentyp, evtl. den Tag- oder Attributnamen, einen Zeiger auf den Vaterknoten und die Länge der Knotenrepräsentation inkl. Inhalt. Dabei wird genutzt, dass die Länge des Knotens und die Position des Vaterknotens durch die Seitengröße begrenzt sind, d.h. es reichen je 2 Byte, um diese Information festzuhalten. Außerdem ist der Tag- oder Attributname nicht als Text, sondern in Form eines Verweises in eine Symboltabelle gespeichert. So benötigt die Codierung der gesamten Strukturinformation eines Knotens nur einen 8Byte-Header. Das ist weniger, als ein Element-Tag mit zwei Zeichen Länge in Textform benötigt (<xx></xx> = 9 Byte!). 9 Natix – ein natives XML-DBMS 4.3 Verteilung eines Dokuments auf mehrere Seiten Zur Repräsentation von Dokumenten, die größer sind als eine Seite, werden in die auf den Seiten gespeicherten Teilbäume so genannte »Proxy«-Knoten eingefügt. Diese Knoten enthalten einen Verweis auf einen weiteren Teilbaum-Datensatz. Ersetzt man alle Proxies rekursiv durch ihre referenzierten Teilbäume, ergibt sich das Gesamtdokument. Jeder Teilbaum-Datensatz enthält außerdem wie oben beschrieben einen Rückzeiger auf den referenzierenden Teilbaum. Diese Darstellung ähnelt dem häufig für Indexstrukturen verwendeten BBaum, nur dass als Schlüssel keine gewöhnlichen Datentypen wie Strings oder Zahlen verwendet werden, sondern Pfade im Dokumentbaum. Auch der Algorithmus zur Erzeugung und Pflege der so auf Seiten verteilten Dokumentstruktur weist Ähnlichkeiten mit den entsprechenden Algorithmen zur Pflege eines B-Baums auf: Beispielsweise wird beim Einfügen eines neuen Knotens zunächst versucht, den Knoten in einen vorhandenen Teilbaum einzufügen. Sollte dies fehlschlagen, weil der resultierende Datensatz nicht mehr auf eine Seite passen würde, wird der Teilbaum in mehrere kleinere zerlegt (Split) und auf neue Hintergrundspeicherseiten verteilt. Dabei kann es bei Knoten mit sehr vielen Kindern auch dazu kommen, dass Teilbaum-Datensätze entstehen, die nur Proxies enthalten, die wiederum auf Proxies verweisen. Dies entspricht dem »Überlauf« in einem B-Baum, der denselben Schlüssel (hier: Pfad) mehrfach enthalten darf. Der genaue Mechanismus findet sich in [KaMo99]. 4.4 Isolation Implementiert man ein natives Datenbanksystem für XML, so bereitet es keine Schwierigkeiten, Sperren auf Dokumentebene anzusiedeln. Dieser Ansatz wird beispielsweise von Tamino verfolgt. Aber auch Sperrprotokolle für feinere Granularitäten wie Dokumentknoten sind möglich. In Natix bietet es sich an, Sperren auf Teilbäumen zu vergeben, die in einem physischen Satz gespeichert sind. Will man ein hohes Maß an Nebenläufigkeit errreichen, so kann man die Semantik der Operationen auf Dokumentknoten 10 ausnutzen und sehr spezifische Protokolle entwerfen. Die Grundlage bilden dabei Ansätze für die Synchronisation von ADTs. Hat man darüber hinaus noch Wissen über die DTD, so lässt sich ein Höchstmaß an Nebenläufigkeit erreichen. Die Beschreibung möglicher Protokolle würde den Rahmen dieses Übersichtsartikels sprengen. Wir verweisen den interessierten Leser daher auf [HeKaMo01]. 5 Auswertung von XML-Anfragen Wie bereits beschrieben, wird zur Auswertung einer deklarativen XML-Anfrage diese in ein Auswertungsprogramm übersetzt und auf der Natix Virtual Machine ausgeführt. Da in Natix wie auch in traditionellen DBMS die Anfrageauswertung algebraisch erfolgt, beschreibt ein Auswertungsprogramm im Wesentlichen die Auswertung eines algebraischen Ausdrucks. Gegenstand dieses Abschnitts ist daher die Übersetzung von deklarativen XML-Anfragen in algebraische Ausdrücke. Als Basis hierfür dient ein kurzer Überblick über die Besonderheiten von deklarativen XML-Anfragen. 5.1 Deklarative XML-Anfragen Vereinfachend dargestellt dient eine XMLAnfrage zur Selektion, Extraktion, Kombination und Restrukturierung von XMLDaten. Die Selektion bezeichnet die Auswahl von Dokumenten aufgrund von Inhalt, Struktur oder anderen Attributen, wie Name, Alter usw. Die Extraktion ist die Auswahl von Dokumentausschnitten, wie Elemente, Textfragmente oder Attributwerte. Zur Extraktion werden bestimmte Methoden zur Adressierung von Ausschnitten in XML-Dokumenten verwendet, wie z.B. Pfadausdrücke. Das Zusammenführen des Inhalts mehrerer XML-Dokumente wird als Kombination bezeichnet. Dies entspricht der Verbund(Join-)Operation in relationalen oder objektorientierten Datenbankmanagementsystemen. Der letzte Punkt, die Restrukturierung, bezeichnet die Transformation oder Umstrukturierung eines XML-Dokuments. Wichtige Anfrageprimitiven hierfür sind geschachtelte Anfragen, Gruppierungen und Ordnungsoperationen. Betrachten wir nun ein paar Beispielanfragen, zu deren Formulierung wir die Anfragesprache XQuery [XQuery] ver- wenden wollen. Dabei handelt es sich um einen der prominentesten Vertreter der zahlreichen Vorschläge für eine deklarative XML-Anfragesprache [RoLaSc98, ChClSi00,DeFeFlLeSu98,RoChFl00]. Wir beschränken uns hier auf XQuery-Anfragen, die aus einer FOR- bzw. LET-Klausel, einer WHERE- und einer RETURN-Klausel bestehen. Die FORbzw. LET-Klausel dient dem Generieren von Variablenbindungen, die in der WHERE-Klausel gefiltert werden. Die Ergebniskonstruktion anhand der gefilterten Variablenbindungen wird in der RETURN-Klausel spezifiziert. Ein- und Ausgabe einer XQuery-Anfrage sind Instanzen einer Erweiterung des XPath-Datenmodells. Somit werden im Wesentlichen XML-Dokumente als Bäume modelliert. Zur Navigation in einem Dokumentbaum bzw. zur Adressierung von Teilen eines Dokumentbaums werden in XQuery Lokalisationspfade (Location Paths) verwendet. Dabei handelt es sich um Pfadausdrücke aus dem XPath-Standard [XPath]. Die Beispielanfragen beziehen sich auf XML-Dokumente, die der in Abbildung 7 dargestellten Document-TypeDefinition (DTD) entsprechen. Die DTD beschreibt die Struktur von Einträgen in einer Bibliographiedatenbank. Die Einträge enthalten Informationen über den Typ der Veröffentlichung, den Titel und die Autoren. Die in Abbildung 8 dargestellte erste Beispielanfrage zeigt die XQuery-Fähigkeiten zur Datenextraktion. Sie ermittelt Konferenzen, die nach 1996 stattgefunden haben. Die FOR-Klausel extrahiert mittels eines Lokalisationspfads die im Dokument bib.xml enthaltenen conference Elemente und bindet diese an die Variable $c. Die Variablenbindungen werden von der WHERE-Klausel gefiltert. Das Filterprädikat überprüft, ob das Veranstaltungsjahr der Konferenz nach 1996 liegt. Für jede der gefilterten Variablenbindungen erzeugt die RETURN-Klausel ein conference Element, dessen Inhalt aus dem Titel und dem Veranstaltungsjahr der Konferenz gebildet wird. Die conference Elemente werden in ein bib Element eingebettet. Während die vorangehende Anfrage eine einfache Extraktion vornimmt, führt die in Abbildung 9 gezeigte Anfrage eine Restukturierung durch. In XQuery wer- Datenbank-Spektrum 1/2001 Natix – ein natives XML-DBMS den dazu geschachtelte Anfragen verwendet. Die Anfrage erzeugt in einem conf-authors Element eine Liste von author Elementen, die neben dem Autorennamen eine Liste der mitverfassten Konferenzartikel enthalten. Die Anfrage besteht aus zwei geschachtelten Anfragen. Die äußere extrahiert die Autoren von Konferenzartikeln aus dem Dokument bib.xml und erzeugt für jeden ein author Element. Die in die FOR-Klausel eingebettete Unteranfrage bestimmt für jeden Autor die Artikelliste. Dazu extrahiert sie alle Konferenzartikel aus dem Dokument bib.xml, die den Autor in ihrer Autorenliste enthalten. 5.2 Natix-Algebra Wie im vorangehenden Abschnitt gezeigt, beruhen XML-Anfragen auf der Bearbeitung von Variablenbindungen. Diese lassen sich effizient in Tabellenstrukturen verwalten. Ausgehend von dieser Überlegung, basiert der Entwurf der Natix-Algebra auf einer Erweiterung einer relationalen Algebra. Die Erweiterung besteht in der Einführung neuer Datentypen zur Abbildung des XPath Datenmodells [XPath] und neuer Operatoren zur Generierung von Variablenbindungen und zur Konstruktion von Ergebnisdokumenten. Wir können an dieser Stelle aus Platzgründen die Natix-Algebra nur kurz skizzieren und verweisen daher für eine detaillierte Beschreibung auf [FiMo01+]. Zur Darstellung von XML-Daten dient der Datentyp XML-Knoten. Entsprechend dem XPath-Datenmodell werden sieben Knotentypen unterschieden: Root, Element, Attribute, Text, NameSpace, ProcessingInstruction und Comment. Um Eigenschaften eines Knoten zu erfragen, wie den Markierungsbezeichner (Tag Name), den Typ oder den Zeichenkettenwert (String Value), stehen Funktionen wie getTagName, getType und getValue zur Verfügung. Die Navigation im Dokumentbaum wird mittels Navigationsfunktionen realisiert. Für die Umwandlung von Relationeninhalten in XML-Ergebnisdokumente stehen Konstruktionsfunktionen zur Verfügung. Die Operatorenmenge der Natix-Algebra besteht aus relationalen Operatoren wie Select, Project und Join zur Bearbeitungen von Relationen. Da die Bearbeitung von XML-Daten weitgehend über Datenbank-Spektrum 1/2001 <!ELEMENT <!ELEMENT <!ELEMENT <!ELEMENT <!ELEMENT <!ELEMENT <!ATTLIST bib (conference|journal)*> conference (title, year, article+)> journal (title, volume, no?, article+) article (title, author+)> title (#PCDATA)> author EMPTY> author last CDATA #REQUIRED first CDATA #REQUIRED> Abb. 7: Eine DTD zur Beschreibung der Struktur von Bibliographiedaten <bib> { FOR $c IN document("bib.xml")/bib/conference WHERE $c/year > 1996 RETURN <conference> <title> {$c/title }</title> <year> {$c/year }</year> </conference> }</bib> Abb. 8: XQuery-Anfrage zur Bestimmung von aktuellen Konferenzen <conf-authors> { FOR $a IN document("bib.xml")//conference/article/author RETURN <author> <name first={$a/@first}last={$a/@last} <articles> { FOR $b IN document("bib.xml")//conference/article, $c IN $/author WHERE $c/@first = $a/@first AND $c/@last=$a/@last RETURN <article> {$b/title}</article> } </articles> </author> }</conf-authors> Abb. 9: XQuery zur Generierung eines Dokuments mit Konferenzautoren Funktionen erfolgt, beinhaltet die NatixAlgebra verschiedene Map-Operatoren, die ein Auswerten von Funktionen auf den Tupeln einer Eingaberelation ermöglichen. Neben den Map-Operatoren führt die Natix-Algebra spezielle Gruppierungsoperatoren ein, die es erlauben, Kombinationen von Gruppierungen auszudrücken, was für die Auswertung von restrukturierenden Anfragen wichtig ist. 5.3 Generieren von Variablenbindungen Das Generieren von Variablenbindungen beruht, wie in den Beispielanfragen gezeigt, auf Lokalisationspfaden. Ein Lokalisationspfad besteht aus einer Sequenz von Lokalisationsschritten (Location Steps). Ein Lokalisationsschritt beschreibt einen Navigationsschritt ausge- hend von einem Kontextknoten in einem Dokumentbaum entlang einer Navigationsachse. Die Navigationsachse bestimmt die Beziehung, die zwischen dem Kontextknoten und den erreichten Knoten besteht. Zur Filterung der durch die Navigation erreichten Knoten können vom Lokalisationsschritt Filterprädikate angewendet werden. Ein Lokalisationsschritt liefert somit in einem Lokalisationspfad eine gefilterte Liste von Knoten, die jeweils den Kontextknoten für den nächsten Lokalisationsschritt bilden. Bei der Auswertung eines Lokalisationspfads wird dieser zunächst in seine Lokalisationsschritte aufgeteilt. Zur Navigation entsprechend der Naviagationsachse wird für jeden Schritt ein UnnestMap-Operator eingeführt. Dabei 11 Natix – ein natives XML-DBMS handelt es sich um einen speziellen MapOperator, der eine im Subskript spezifizierte mengenwertige Funktion auf den Tupeln der Eingaberelation auswertet und diesen das entschachtelte Funktionsergebnis als zusätzliches Attribut hinzufügt. Zur Auswertung eines Lokalisationsschritts besteht das Subskript aus einer Navigationsfunktion. Dabei handelt es sich um eine Funktion, die zu einem XML-Knoten eine geordnete Menge von Knoten entsprechend einer Navigationsachse bestimmt. Beispiele hierfür sind die Funktionen getParent, getChildren, getDescendantsOrSelf und getAttributes. Zur Filterung der durch eine Navigation erreichten Knoten kann den Navigationsfunktionen ein Bezeichner als zusätzlicher Parameter übergeben werden, um nur Knoten mit einem bestimmten Namen zu selektieren. Weitere Filterprädikate können mittels eines Select-Operators angewendet werden. Startet der auszuwertende Lokalisationspfad vom Wurzelknoten eines über eine URI spezifizierten Dokuments, wird ein ExpressionScan-Operator zusammen mit der getDocumentRoot Funktion verwendet, die zu einer URI den Wurzelknoten des entsprechenden Dokuments ermittelt. Der ExpressionScan-Operator liest keine Eingaberelation sondern wertet lediglich eine im Subskript spezifizierte Funktion aus und wandelt das Ergebnis in einen Tupelstrom um. Abbildung 10 zeigt den Operatorbaum der übersetzten Anfrage aus Abbildung 8. Der ExpressionScan bindet die Wurzel des Dokuments bib.xml an die Variable $d. Die anschließenden UnnestMap-Operatoren binden die im Dokument enthaltenen bib-Elemente an die Variable $b und die conference-Elemente an die Variable $c. Die den UnnestMap-Operatoren folgenden Map-Operatoren binden das erste title und year Kindelement des an $c gebundenen XML-Knotens, an die Variablen $t und $y. Für den Zugriff auf den ersten Knoten in einer geordneten Menge, wie sie von einer Navigationsfunktion geliefert wird, wird hier die Funktion getFirst verwendet. Das Filtern der Variablenbindungen erfolgt durch einen SelectOperator. Dessen Filterprädikat überprüft, ob das an $y gebundene year-Element eine Jahresangabe enthält, die größer als 1996 ist. 12 5.4 Ergebniskonstruktion Die Ergebniskonstruktion erfolgt durch das Anwenden von Konstruktionsfunktionen auf Variablenbindungen. Diese übermitteln das Ergebnis der Anfrage per Seiteneffekt an die Anwendung. Im einfachsten Fall handelt es sich bei den Konstruktionsfunktionen um Ausgabefunktionen zur Konstruktion einer textuellen Darstellung. Für eine effizientere Form der Ergebnisweiterleitung ist es auch möglich, Konstruktionsfunktionen zu verwenden, die SAX-Events generieren. Die Konstruktionsfunktionen werden, wie die Navigationsfunktionen bei der Variablenbindungsgenerierung, als Subskript für Map-Operatoren verwendet. Der Auswertungsplan in Abbildung 10 enthält zur Ergebniskonstruktion einen FL-Map-Operator. Dessen Subskript besteht aus drei Funktionen, first, each und last. Die first Funktion wird auf dem ersten, die last Funktion auf dem letzten und die each Funktion auf jedem Tupel der Eingaberelation ausgewertet. Im Beispielplan erzeugt die first Funktion die Startmarkierung (Start-Tag) des bib Elements, dessen Inhalt aus dem Anfrageergebnis besteht. Die each Funktion erzeugt ein conference Element mit dem Konferenztitel und dem Veranstaltungsjahr. Die last Funktion schließt die Ergebniskonstruktion ab und erzeugt dazu die Endemarkierung des bib Elements. Zur Auswertung restrukturierender Anfragen und zum Entschachteln von XQuery-Anfragen sind in Natix spezielle Gruppierungsoperatoren vorgesehen, die ein Kombinieren von Gruppierungsoperationen ermöglichen. Einen entsprechenden Operatorbaum, der der Übersetzung der Anfrage aus Abbildung 9 entspricht, zeigt Abbildung 11. An die UnnestMap- und Map-Operatoren, die die Variablenbindungen erzeugen, schließen sich die Operatoren zur Ergebniskonstruktion an. Da es sich bei der Anfrage um eine restrukturierende Anfrage handelt, werden zur Ergebniskonstruktion die Variablenbindungen mittels des Groupify/GroupApply-Operatorenpaars gruppiert. Der Groupify Operator führt eine Gruppierung der Eingaberelation durch, die durch die im Subskript spezifizierte group-by Liste definiert wird. Zwischen den Operatoren ist ein Teilplan eingebettet, der auf jeder Gruppe ausgewertet wird. Zur Ergebniskonstruktion FL−Map first: <bib> each: <conference> <title>getValue($t)</title> <year>getValue($y)</year> </conference> last: </bib> Select getValue($y) > 1996 Map $t: getFirst(getChildren($c,"title")) Map $y: getFirst(getChildren($c,"year")) UnnestMap $c: getChildren($b,"conference") UnnestMap $b: getChildren($d,"bib") ExpressionScan $d: getDocumentRoot("bib.xml") Abb. 10: Als Operatorbaum dargestellter algebraischer Ausdruck zur Auswertung der Anfrage in Abbildung 8 enthält das Subskript des Groupify Operators eine first Funktion, die vor dem eingebetteten Teilplan ausgewertet wird. Zusätzlich enthält das Subskript des GroupApply Operators eine last Funktion, deren Auswertung nach der des eingebetteten Teilplans für jede Gruppe erfolgt. 6 Fazit Wir haben anhand ausgewählter Module von Natix gezeigt, wie die Nachteile relationaler Datenbanksysteme durch spezielle Implementierungen behoben werden können. Effektive und effiziente Lösungen für die Verarbeitung von XML sind auch in anderen Modulen notwendig: • Anwendungsprogrammierschnittstellen für DOM und SAX, • XQuery- und XPath-Compiler und • Transaktionsmanagement. Die Implementierungen der vorhandenen Entwürfe für diese Module befinden sich in unterschiedlichen Stadien. Datenbank-Spektrum 1/2001 Natix – ein natives XML-DBMS Literatur FL−Map first: each: last: </bib> GroupApply last: </articles> </author> FL−Map first: each: <article> <title>$c</title> </article> last: Groupify group−by: $f,$l first: <author> <name first=$f last=$l/> <articles> FL−Map first: <bib> each: last: Map $f: getValue(getAttribute($a,"first")) Map $l: getValue(getAttribute($a,"last")) Map $t: getFirst(getChildren($ar,"title")) UnnestMap $a: getChildren($ar,"author") UnnestMap $ar: getChildren($c,"article") UnnestMap $c:getChildren($b,"conference") UnnestMap $b: getChildren($d,"bib") ExpressionScan $d: document("bib.xml") Abb. 11: Als Operatorbaum dargestellter algebraischer Ausdruck zur Auswertung der Anfrage aus Abbildung 9 Datenbank-Spektrum 1/2001 [ChClSi00] V. Christophides, S. Cluet, J. Simeon: On wrapping query languages and efficient XML integration. In: Proc. of the ACM SIGMOD Conf. on Management of Data, pages 141-152, 2000. [DeFeFlLeSu98] A. Deutsch, M. Fernandez, D. Florescu, A. Levy, D. Suciu: XML-QL: a query language for XML. Technical report, World Wide Web Consortium, 1989. http:// www.w3.org/TR/NOTE-xml-ql. [DOM] L. Wood et al: Document object model (DOM) level 1 specification (second edition). Technical report, World Wide Web Consortium, 2000. W3C Working Draft 29-Sept2000. [FlKo99] D. Florescu, D. Kossmann: Storing and querying XML data using an RDBMS. IEEE Data Engineering Bulletin, 22(3):27-34, 1999. [FiMo00] T. Fiebig, G. Moerkotte: Evaluating Queries on Structure with eXtended Access Support Relations. In: WebDB 2000, 2000. Extended Version: [FiMo01]. [FiMo01] T. Fiebig, G. Moerkotte: Evaluating Queries on Structure with eXtended Access Support Relations. In: D. Suciu and G. Vossen, editors, The World Wide Web and Databases, LNCS 1997, pages 125-136. Springer, 2001. [FiMo01+] S. Fiebig, G. Moerkotte: Algebraic XML Construction in Natix. Technical Report 16, University of Mannheim, 2001. [HeKaMo01] S. Helmer, C.-C. Kanne, G. Moerkotte: Isolation in XML bases. Technical Report 15, University of Mannheim, 2001. [KaMo99] C.-C. Kanne, G. Moerkotte: Efficient storage of XML data. Technical Report 08/99, University of Mannheim, Mannheim, Germany, 1999. [KlMe00] M. Klettke, H. Meyer: XML and object-relational database systems – enhancing structural mappings based on statistics. In: ACM SIGMOD Workshop on the Web and Databases (WebDB), 2000. [RoChFl00] J. Robie, D. Chamberlin, D. Florescu: Quilt: An XML Query Language for Heterogeneous Data Sources. In: International Workshop on the Web and Databases, 2000. [RoLaSc98] J. Robie, J. Lapp, D. Schach: XML Query Language (XQL), 1998. http:// www.w3.org/TandS/QL/QL98/pp/xql.html. [SAX] D. Megginson: Megginson Technologies. http://www.megginson.com/SAX/. [ScKeWiWa00] A. Schmidt, M. Kersten, M. Windhouwer, and F. Waas: Efficient relational storage and retrieval of XML documents. In: ACM SIGMOD Workshop on the Web and Databases (WebDB), 2000. [ShGaTuYhDeNa99] J. Shanmugasundaram, H. Gang, K. Tufte, C. Yhang, D. J. DeWitt, J. Naughton: Relational databases for querying XML documents: Limitations and opportunities. In: Proc. Int. Conf. on Very Large Data Bases (VLDB), pages 302-314, 1999. [SuRiLo00] B. Surjanto, N. Ritter, H. Loeser: XML content management based on objectrelational database technology. In: Proc. 1st Int. Conf. on Web Information Systems Engineering WISE 2000), pages 64-73, 2000. [XML] T. Bray, J. Paoli, C. M. Sperberg-McQueen: Extensible markup language (XML) 1.0. Technical report, World Wide Web Consortium, 1998. W3C Recommendation 10Feb-98. [XPath] J. Clark, S. DeRose: XML path language (XPath) version 1.0. Technical report, World Wide Web Consortium, 1999. W3C Recommendation. [XQuery] D. Chamberlin, J. Clark, D. Florescu, J. Robie, J. Simeon, M. Stefanescu: Xquery 1.0: An XML query language. Technical report, World Wide Web Consortium, 2001. W3C Working Draft 07 June 2001. [YoAmShUe01] M. Yoshikawa, T. Amagasa, T. Shimura, S. Uemura: Xrel: A path-based approach to storage and retrieval of XML documents using relational databases. ACM Transactions on Internet Technology, 1(1), June 2001. Thorsten Fiebig, Guido Moerkotte Universität Mannheim Fakultät für Mathematik und Informatik 68131 Mannheim {thorsten, moerkotte}@informatik.uni-mannheim.de Carl-Christian Kanne data ex machina GmbH Bergstr. 157a 69121 Heidelberg [email protected] 13