Entwicklung einer Software-Komponente zur Wartung von Laufzeitlexika Magisterarbeit in der Philosophischen Fakultät II (Sprach- und Literaturwissenschaften) der Friedrich-Alexander-Universität Erlangen-Nürnberg vorgelegt von Martin Scherbaum aus Ebern Dank Meine Magisterarbeit möchte ich meiner Familie widmen, die mich in allen meinen Unternehmungen immer mit viel Verständnis und Wohlwollen unterstützt hat. Weiterhin möchte ich auf diesem Weg meiner Lehrerin Marga Kestler und meinen Lehrern Konrad Schrott und Dr. Friedrich Wölfel danken, die schon in frühen Jahren mein Interesse an der Sprache und ihren Strukturen geweckt haben, und ohne deren frühe Förderung ich wohl nicht zur Linguistik gekommen wäre. In bezug auf diese Arbeit gilt mein besonderer Dank meinen Kommilitonen Gerald Schüller, Björn Beutel, Marco Zierl, Yves Forkl und Oliver Lorenz, mit denen ich viele meiner Ideen und Probleme diskutieren konnte und denen immer wieder neue “features” einfielen, die ich noch in mein Projekt aufnehmen bzw. verbessern konnte. Besonders erwähnen möchte ich T. Harri Gohlisch, der – selbst an seiner Dissertation arbeitend – immer einen guten Rat von der Warte des erfahreneren Kommilitonen und Freundes für mich hatte. Vielen Dank. Danken möchte ich auch meinen beiden betreuenden Professoren, Herrn Professor Dr. Hausser für sein hartnäckiges Nachbohren an den Stellen, die ich zu vernachlässigen drohte, und durch das ich einige fruchtbare Problemlösungen finden konnte, und Herrn Professor Dr. Schneider, über dessen bereitwillige Übernahme der Zweitbetreuung ich mich sehr gefreut habe. Zuletzt möchte ich mich bei allen Freunden und Bekannten bedanken, die mir durch ihren Zuspruch in “schwachen Momenten” geholfen haben, meine Magisterarbeit mit viel Spaß an der Arbeit zu Ende zu bringen. Inhaltsverzeichnis 1 2 3 Einleitung 1 1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Zielsetzung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 Voraussetzungen . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Das Lexikon 5 2.1 Was ist ein Lexikon? . . . . . . . . . . . . . . . . . . . . . . . . 5 2.1.1 Die traditionelle Sicht des Lexikons . . . . . . . . . . . . 5 2.1.2 Die Sicht der Computerlinguistik . . . . . . . . . . . . . 6 2.2 Die LA-Grammatik und das Lexikon . . . . . . . . . . . . . . . . 8 2.3 Das MALAGA-Format für Lexikoneinträge und Analysepfade . . 10 2.4 Klartextlexikon und Laufzeitlexikon . . . . . . . . . . . . . . . . 11 2.5 Lexikoneinträge in Datenbanken . . . . . . . . . . . . . . . . . . 12 Beschreibung der zu verarbeitenden Daten 14 3.1 Die verschiedenen Datentypen . . . . . . . . . . . . . . . . . . . 14 3.2 Die Beziehungen zwischen den verschiedenen Datentypen . . . . 16 3.3 Einflüsse von Homonymie und Polysemie auf die Lexikoneintragsstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Berücksichtigung der Polysemie und Homonymie in der LDB . . 21 3.4 i 4 Datenbanken 25 4.1 Was ist eine Datenbank? . . . . . . . . . . . . . . . . . . . . . . 25 4.2 Ebenen der Datenbeschreibung . . . . . . . . . . . . . . . . . . . 27 4.3 Datenmodelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.4 Netzwerkdatenbanken . . . . . . . . . . . . . . . . . . . . . . . . 29 4.4.1 Verbunde . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4.4.2 Mengen . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.4.3 Anwendung von Mengen und Verbunden . . . . . . . . . 32 4.4.4 Beschreibung der Beziehungen zwischen Verbunden . . . 34 4.4.5 Weitere Datenstrukturen in Netzwerkdatenbanken . . . . . 34 4.4.6 Datenbanksprachen in Netzwerkdatenbanken . . . . . . . 35 Weitere grundlegende Begriffe zu Datenbanken . . . . . . . . . . 36 4.5.1 Transaktionen . . . . . . . . . . . . . . . . . . . . . . . . 36 4.5.2 Verwaltung mehrerer Benutzer durch Sperrungen . . . . . 37 4.5 5 Datenbankkonzepte in der Lexikondatenbank 5.1 Die Lexikondatenbank als Netzwerkdatenbank 39 . . . . . . . . . . 39 5.1.1 Verbunde . . . . . . . . . . . . . . . . . . . . . . . . . . 39 5.1.2 Mengen . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 5.1.3 Operationen und Zugriffsfunktionen . . . . . . . . . . . . 41 5.2 Funktionale Gliederung der Lexikondatenbank . . . . . . . . . . 42 5.3 Das Konzept der Teildatenbanken . . . . . . . . . . . . . . . . . 43 5.4 Anforderungen an den Suchschlüssel . . . . . . . . . . . . . . . . 45 5.4.1 Datenbanken mit festgelegter Maximallänge für Suchschlüssel . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Elemente mit variabler Größe in den Teildatenbanken . . . 47 Der Sperrmechanismus . . . . . . . . . . . . . . . . . . . . . . . 48 5.4.2 5.5 5.6 6 Die Benutzerverwaltung . . . . . . . . . . . . . . . . . . . . . . 49 Die Implementation der Lexikondatenbank 51 6.1 Aufbau der verwendeten Teildatenbanken . . . . . . . . . . . . . 51 6.1.1 Der Indexbaum . . . . . . . . . . . . . . . . . . . . . . . 52 6.1.2 Die Schlüsselsatztabelle . . . . . . . . . . . . . . . . . . 58 6.1.3 Datensätze . . . . . . . . . . . . . . . . . . . . . . . . . 60 6.1.4 Der Datenbank-Deskriptor . . . . . . . . . . . . . . . . . 61 6.1.5 Sperren von Datensätzen . . . . . . . . . . . . . . . . . . 62 Das Konzept der Eingangs- und Ausgangsfilter . . . . . . . . . . 63 6.2.1 Verwendete Datenformate . . . . . . . . . . . . . . . . . 63 6.2.2 Die Filterfunktionen . . . . . . . . . . . . . . . . . . . . 65 6.2.3 Kommunikation mit LDB-externen Programmen . . . . . 67 6.2.4 Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.2.5 Pipes in der LDB . . . . . . . . . . . . . . . . . . . . . . 69 6.2.6 Schlüsselextraktion, Allomorphgenerierung und Allomorphdekodierung . . . . . . . . . . . . . . . . . . . . . 71 Die Lexikondatenbank . . . . . . . . . . . . . . . . . . . . . . . 77 6.3.1 Verwaltungsdatenstrukturen der Lexikondatenbank . . . . 77 6.3.2 Die Indextabelle . . . . . . . . . . . . . . . . . . . . . . 78 6.3.3 Das Aufbauen der Verbindungen zwischen den Teildatenbanken . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.3.4 Die Benutzerverwaltung der Lexikondatenbank . . . . . . 81 6.3.5 Fehlerbehandlung . . . . . . . . . . . . . . . . . . . . . . 82 6.2 6.3 6.4 Der Umgang der Lexikondatenbank mit Speicherressourcen . . . 85 6.4.1 Speicherplatzbedarf der Datenbankdaten . . . . . . . . . 85 6.4.2 Komprimierung der Datensätze . . . . . . . . . . . . . . 92 7 Netzwerkkommunikation 97 7.1 Das Client-Server-Konzept . . . . . . . . . . . . . . . . . . . . . 97 7.2 Strukturen für die Netzwerkkommunikation . . . . . . . . . . . . 101 7.3 8 Das ISO-OSI-7-Schichten-Modell . . . . . . . . . . . . . 101 7.2.2 Remote Procedure Calls . . . . . . . . . . . . . . . . . . 102 Netzwerkkommunikation in der Lexikondatenbank . . . . . . . . 106 7.3.1 Remote Procedure Calls in der LDB . . . . . . . . . . . . 107 7.3.2 Simulation einer Duplex-Verbindung . . . . . . . . . . . 108 Beschreibung der erstellten Programme 111 8.1 Konfigurationsdateien . . . . . . . . . . . . . . . . . . . . . . . . 111 8.2 Server- und Clientprogramme 8.3 9 7.2.1 . . . . . . . . . . . . . . . . . . . 114 8.2.1 Das Serverprogramm ldb . . . . . . . . . . . . . . . . . . 114 8.2.2 Die Testshell ldbsh . . . . . . . . . . . . . . . . . . . . . 116 8.2.3 Die Client-Schnittstelle ldbcall . . . . . . . . . . . . . . . 118 8.2.4 Kompatibilität . . . . . . . . . . . . . . . . . . . . . . . 120 Die graphische Benutzeroberfläche xLDB . . . . . . . . . . . . . 120 8.3.1 Die Programmiersprache TCL und das TK Toolkit . . . . 120 8.3.2 Vorteile einer graphischen Benutzeroberfläche 8.3.3 Die Anforderungen an xLDB . . . . . . . . . . . . . . . . 124 8.3.4 Eine Sitzung mit xLDB . . . . . . . . . . . . . . . . . . . 126 8.3.5 Kompatibilität . . . . . . . . . . . . . . . . . . . . . . . 132 Zusammenfassung . . . . . . 122 133 9.1 Mögliche Verbesserungen . . . . . . . . . . . . . . . . . . . . . . 135 9.2 Anschlußarbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Literaturverzeichnis 110 A Befehle der Testshell ldbsh A.1 Befehle zur Manipulation des Servers A.2 Befehle zur Ermittlung des Zustands der geöffneten Datenbank A.3 Befehle, um Dienste des Servers zu erhalten A.4 Befehle, die nur die Shell betreffen B Quelltext der Lexikondatenbank-Programme B.1 Allgemeine, globale Module B.2 Module für Remote Procedure Calls B.3 Client-Module B.4 Server-Module C Quelltext des xLDB-Programms Abbildungsverzeichnis 3.1 Verweise zwischen Datentypen . . . . . . . . . . . . . . . . . . . 18 3.2 Datentypen in der Lexikondatenbank nach dem EntityRelationship-Modell . . . . . . . . . . . . . . . . . . . . . . . . 24 4.1 Beispiel eines Verbundes der Lexikondatenbank . . . . . . . . . . 30 4.2 Beispiel einer Menge der Lexikondatenbank . . . . . . . . . . . . 31 5.1 Funktionale Teilbereiche der Lexikondatenbank . . . . . . . . . . 42 5.2 Bestandteile einer Teildatenbank . . . . . . . . . . . . . . . . . . 43 5.3 Beispiel für das Fragmentieren einer Datensatzdatei . . . . . . . . 48 6.1 Zugriffstruktur mit einfachen Schlüsselzeichenketten . . . . . . . 52 6.2 Beispiel einer B-Baum-Seite . . . . . . . . . . . . . . . . . . . . 53 6.3 Beispiel eines B-Baums . . . . . . . . . . . . . . . . . . . . . . . 54 6.4 Zugriffsstruktur mit indirekter Indizierung der Datensätze . . . . . 59 6.5 Beispiel eines Schlüsselsatzes . . . . . . . . . . . . . . . . . . . 60 6.6 Datenbankmodule mit Eingabe- und Ausgabefilter . . . . . . . . . 66 6.7 Prozesse in einer unidirektionalen Pipe . . . . . . . . . . . . . . . 69 6.8 Prozesse in einer bidirektionalen Pipe . . . . . . . . . . . . . . . 70 6.9 Funktionsgruppen in MALLEX . . . . . . . . . . . . . . . . . . 73 6.10 Funktionsgruppen in MALFIL . . . . . . . . . . . . . . . . . . . 74 ii 6.11 Flußdiagramm der Funktion addEditEntry . . . . . . . . . . . . . 96 7.1 Das Client-Server-Konzept . . . . . . . . . . . . . . . . . . . . . 98 7.2 Client-Server-Konzept mit Zugangsregelung . . . . . . . . . . . . 101 7.3 Ablauf eines Remote Procedure Calls . . . . . . . . . . . . . . . 104 8.1 Schematische Darstellung der Verbindung zwischen xLDB und LDB 125 8.2 Der Startbildschirm xLDBs . . . . . . . . . . . . . . . . . . . . . 126 8.3 Darstellung eines Lexikoneintrags durch xLDB . . . . . . . . . . 127 8.4 Texteingabefenster mit Schablonenmenü . . . . . . . . . . . . . . 130 Tabellenverzeichnis 6.1 Speicherbedarf der einzelnen Teildatenbanken der LDB . . . . . . 86 6.2 Speicherbedarf der Komponenten einer Teildatenbank . . . . . . . 86 6.3 Speicherbedarf der Lexikondaten ohne die LDB . . . . . . . . . . 87 6.4 Gegenüberstellung des Speicherplatzbedarfs . . . . . . . . . . . . 87 6.5 Speicherbedarf der Lexikondatenbank nach dem Defragmentieren 90 6.6 Gesamtbedarf der LDB an Vordergrundspeicher . . . . . . . . . . 91 6.7 Größe der Lexikondatei vor und nach dem Komprimieren . . . . . 93 6.8 Ergebnisse der Analyse der Eintragslängen 93 8.1 EBNF-Darstellung des Formats der Konfigurationsdateien . . . . 113 iii . . . . . . . . . . . . Kapitel 1 Einleitung 1.1 Motivation Die Abteilung Computerlinguistik am Institut für Deutsche Sprach- und Literaturwissenschaft der Universität Erlangen-Nürnberg verfügt über ein System zur morphologischen und syntaktischen Analyse und Generierung (MALAGA1). MALAGA ist sowohl der Name einer Programmiersprache zur Verarbeitung grammatischer Problemstellungen und eines Programms, um in dieser Programmiersprache geschriebene Grammatiken abzuarbeiten. Dabei folgt es der Theorie der Linksassoziativen Grammatik wie in [15] vorgestellt. Im Gegensatz zu statistischen Analyseverfahren, die ihre Analysen auf der Basis von schon analysierten Texten erstellen, arbeitet MALAGA regelbasiert. Dafür benötigt MALAGA spezielle Regeln und ein Lexikon, auf das die Regeln angewendet werden. Ein solches Lexikon wurde in mehreren Jahren aufgebaut. Mittlerweile hat es einen Umfang von ca. 20.000 Grundformeinträgen. Das Lexikon wird ständig von mehreren Mitarbeitern gewartet, indem sie es erweitern oder bestehende Lexikoneinträge korrigieren. Dabei greifen sie häufig gleichzeitig auf das Lexikon zu. Da das Lexikon bisher in Form einfacher ASCII-Dateien vorliegt und auf diese nach den Wortarten verteilt ist, kommt es immer wieder vor, daß sich die Lexikonbearbeiter in ihrer Arbeit dadurch behindern, daß der Teil des Lexikons, den sie gerade bearbeiten wollen, schon von einem anderen Mitarbeiter bearbeitet wird. 1 MALAGA ist ein selbstreferenzierendes Akronym für MALAGA Accepts LeftAssociative Grammars with Attributes. MALAGA wird beschrieben in [3] 1 KAPITEL 1. EINLEITUNG 2 Im wesentlichen liegt das Problem darin, daß jeder Bearbeiter, der z.B. die Lexikondatei, die die Substantive enthält (ca. 8.500 Einträge), in seinen Editor lädt, dadurch eine Kopie dieser Datei im Hauptspeicher seines Rechners anlegt. Durch das Bearbeiten eines Lexikoneintrags wird diese Kopie gegenüber der Originaldatei verändert. Wenn zufällig ein anderer Lexikonbearbeiter diesselbe Datei in seinem Editor bearbeitet, hat er eine sowohl gegenüber dem Original als auch gegenüber der Kopie des ersten Bearbeiters veränderte Version vorliegen. Beim Zurückschreiben der veränderten Versionen würden sich die unterschiedlichen Kopien der einzelnen Bearbeiter nacheinander überschreiben. Bis auf die zuletzt gespeicherte Version würden alle anderen Änderungen verloren gehen. Es ist nicht einsichtig, daß ein Lexikonbearbeiter dadurch, daß er einen von 8500 Einträgen ändern will, die übrigen fast 8.500 Einträge der betreffenden Datei für die gleichzeitige Bearbeitung durch andere Bearbeiter blockiert, zumal die meisten dieser Veränderungen nur lokale Auswirkungen auf einen oder einige wenige Lexikoneinträge haben. Die neuen oder geänderten Einträge müssen sodann für die Benutzung durch MALAGA aufbereitet werden. Dabei durchlaufen die Einträge in einem Batchjob mehrere Verarbeitungsprozesse bis schließlich die Zugriffstrukturen von MALAGA erstellt sind. Es handelt sich dabei um die syntaktische Überprüfung, die Allomorphgenerierung und das Erzeugen der Trie-Structure2 . Sehr aufwendig, vor allem in zeitlicher Hinsicht, ist die Allomorphgenerierung. Das liegt vor allem auch daran, daß durch die Anwendung von Allomorphregeln auf die Lexikoneinträge komplexes linguistisches Wissen umgesetzt wird. Die Allomorphgenerierung muß durch die Struktur des Allomorphgenerators immer für jeweils das gesamte Lexikon vorgenommen werden, auch wenn nur ein Eintrag des Lexikons geändert oder hinzugefügt bzw. gelöscht wurde. Die syntaktische Überprüfung der Lexikoneinträge und das Generieren der Trie-Structure fallen, verglichen mit der für die Allomorphgenerierung aufgewendeten Zeit, kaum ins Gewicht. Es ist also angebracht, nach Konzepten zu suchen, die die für die Allomorphgenerierung aufgewendete Zeitspanne minimieren. Ein wesentlicher Schritt dazu ist es, die eben beschriebenen Vorgänge nicht auf das gesamte Lexikon, sondern nur auf die betroffenen Einträge anzuwenden. Welche Änderungen in der Arbeitsweise der benötigten Programme vorzunehmen sind, muß immer im Zusammenhang mit der Art und Weise, wie das Lexikon bearbeitet und verwaltet wird, gesehen werden. Zum Bearbeiten des Lexikons wird bisher fast ausschließlich der Editor “GNU 2 Ein Trie ist eine Sonderform eines digitalen Suchbaums und besonders für die Suchproblematik in MALAGA geeignet. Tries werden ausführlich in [21], S. 481 beschrieben. KAPITEL 1. EINLEITUNG 3 Emacs”3 benutzt. Er ist über Makros und einen eingebauten LisP-Dialekt (ELisP) zu programmieren und bietet bereits ohne Erweiterungen vielfältige Texteditionsmöglichkeiten. Durch veschiedene Erweiterungen wird der Emacs befähigt, UNIX-Befehle auszuführen, etc. Es geht jedoch über die Möglichkeiten des Emacs hinaus, ein Lexikon zu verwalten. Dies ist mit vertretbarem Aufwand und hinreichender Geschwindigkeit mit dem Emacs nicht zu erreichen. Zusammenfassend sind folgende Schwerpunkte einer Lexikonverwaltung, insbesondere der Verwaltung des Lexikons der Computerlinguistik Erlangen, zu nennen: mehrere Bearbeiter gleichzeitig Zugriff auf einzelne Einträge des Lexikons hohe Geschwindigkeit beim Zugriff auf Lexikoneinträge Aufbereitung der Lexikondaten für die Benutzung mit MALAGA Wahrung der Konsistenz der Lexikondaten (Elimination doppelter Einträge) Möglichkeit, die Ergebnisse der Allomorphgenerierung direkt zu kontrollieren Durch die oben genannten Punkte ergibt sich die Folgerung, das Lexikon mit einer Datenbank zu verwalten. Über den rein technisch-informatischen Datenverwaltungsaspekt hinaus muß diese Lexikondatenbank aber auch die linguistische Aufbereitung und linguistisch adäquate Repräsentation der Daten des Lexikons übernehmen. 1.2 Zielsetzung Die Hauptaufgabe dieser Arbeit ist die Implementierung einer Lexikondatenbank4 . Sie muß die Kriterien zur Verwaltung des für MALAGA benötigten Lexikons erfüllen. Diese sind das Speichern, Wiederfinden und Löschen von Lexikoneinträgen. Daneben muß der Zugriff auf die LDB über ein Rechnernetzwerk erfolgen können. Dabei ist der gegenseitige Ausschluß mehrerer Lexikonbearbeiter beim Zugriff auf denselben Eintrag des Lexikons zu garantieren. Weiterhin soll das Datenbankprogramm die Tätigkeiten der Lexikonbearbeiter protokollieren, so daß die Entwicklung des Lexikons nachvollzogen werden kann. 3 [32], 4 Die [29] Bezeichnung Lexikondatenbank wird im Verlauf dieser Arbeit mit LDB abgekürzt. KAPITEL 1. EINLEITUNG 4 Eine weitere Aufgabe besteht darin, exemplarisch ein Programm zu implementieren, das demonstriert, wie eine Anwendung den Zugang zur Datenbank (engl. front end) erhält. Dieses Programm soll in Form eines einfachen Lexikonbetrachters bzw. -editors ausgeführt werden. 1.3 Voraussetzungen Das Projekt der LDB ist in der Computerlinguistik Erlangen kein Einzelprojekt ohne Bezüge zu anderen Projekten. Ihm geht eine lange Entwicklung des Umfeldes, in das die LDB integriert werden soll, voraus. Parallel dazu sind einige Projekte im Entstehen begriffen, die u.U. mit der LDB zusammenarbeiten sollen. Eine wichtige Vorarbeit lieferte Gerald Schüller mit der Implementierung des Vorläufers der hier verwendeten Teildatenbanken5 . Dieses monolithisch konzipierte Projekt verfügte schon über Grundfunktionen wie Einfügen und Löschen eines Eintrags, Ausgeben des Indexbaums und des Datenbankinhalts. Björn Beutel fing fast zeitgleich mit dem Beginn der vorliegenden Arbeit mit der Implementierung von MALAGA an. Mit MALAGA wurde ein neues Lexikonformat eingeführt, was die Strukturierung der LDB und vor allem des Lexikonbetrachters erheblich beeinflußte. Hierauf wird im weiteren noch näher eingegangen. Durch die Verknüpfungen zwischen den verschiedenen Projekten kam es zu vielen “Seiteneffekten”, vor allem zwischen dieser Arbeit und der von Björn Beutel. Für weitergehende Informationen sei auf die Diplomarbeit von Björn Beutel [3] verwiesen. 5 Gerald Schüller implementierte versuchsweise eine Datenbankstruktur, um Analyseergebnisse der morphologischen Wortformerkennung darzustellen und auszuwerten. Zu seiner Implementation existiert keine Dokumentation Kapitel 2 Das Lexikon 2.1 Was ist ein Lexikon? In dieser Arbeit geht es um die Verwaltung eines Lexikons. Also muß zuerst beschrieben werden, was man im allgemeinen unter einem Lexikon versteht und auf welche speziellen Aspekte des Lexikons im Falle dieser Arbeit Rücksicht genommen werden muß. 2.1.1 Die traditionelle Sicht des Lexikons Die erste Begriffsfassung beschreibt das Lexikon in seiner Eigenschaft als Buch zum Nachschlagen. Das Lexikon ist ein “Inventar bzw. Liste/Zusammenstellung der zu einer Zeit geltenden Wörter einer natürlichen Sprache, [...], in alphabetischer Reihenfolge oder in begrifflich-systematischer Anordnung.”1 . Jedem Wort wird ein Lexikoneintrag zugeordnet. Mit “Wort” sind in diesem Fall auch Wortkompositionen oder flektierte Wortformen2 gemeint, die der jeweilige Lexikonbearbeiter aus ihm wichtigen Gründen im Lexikon vertreten sehen wollte. Lexika dienen in irgendeiner Form dem Nachschlagen von Wörtern, Begriffen, etc. Deshalb sind Lexika in irgendeiner Weise sortiert. Das Sortierkriterium hängt von 1 [22], 2 Zum S. 649 Begriff der Wortform vgl. 2.2 5 KAPITEL 2. DAS LEXIKON 6 der intendierten Anwendung des Lexikons ab. Lexika können zum Beispiel nach Sachgruppen oder Herkunft des Wortes sortiert sein. Die Mehrzahl der Lexika ist jedoch – zumindest in dessen einzelnen Abschnitten – alphabetisch sortiert, um dem Anwender einen schnellen Zugriff auf einzelne Einträge zu ermöglichen. Aus linguistischer Sicht ist das Lexikon neben den grammatischen Regeln (z.B. in Phonologie, Morphologie, Syntax etc.) Teil der Grammatik einer Sprache. Das Lexikon umfaßt den gesamten Wortschatz einer Sprache. “The total list of words for any language is referred to as its lexicon.”3 Das Lexikon beschreibt also die lexikalischen (Grund-) Elemente einer Sprache, die Lexeme, die nicht mehr aus anderen abgeleitet werden können. Mit den Mitteln der Morphologie (Flexion, Derivation und Komposition) können aus den Lexemen weitere, neue Wörter und Wortformen gebildet werden. Die einzelnen Einträge des Lexikons können sehr komplex sein. Sie enthalten zum Beispiel Informationen zu phonetisch-phonologischen, morphologischen, syntaktischen, semantischen und/oder pragmatischen Aspekten eines “lexikalischen Formativs”4 . Hierbei müssen auf semantischer Ebene die verschiedenen Lesarten (Bedeutungen) eines Lexikoneintrags berücksichtigt werden. Die Sortierung des Lexikons ist in der Linguistik nur bedingt von Wichtigkeit. Eine nichtalphabetische Sortierung kann z.B. zugunsten einer Gliederung nach sprachlichen Phänomenen oder Wortarten nicht erwünscht sein. Viel mehr als an der Sortierung ist die Sprachwissenschaft an der Vollständigkeit und sprachlichen Abdeckung des Lexikons interessiert. Möglichst alle Wörter bzw. begrifflichen Einheiten eines Sprachsystems sollen erfaßt und beschrieben werden. Um diesem Anspruch gerecht zu werden, muß das Lexikon, dem aktuellen Zustand des jeweiligen Sprachsystems folgend, ständig aktualisiert werden. 2.1.2 Die Sicht der Computerlinguistik In der Computerlinguistik erhält der Begriff des Lexikons zusätzliche wichtige Aspekte. Wichtigster Aspekt ist hier die Computerlesbarkeit und maschinelle Verarbeitbarkeit des Lexikons. Das Lexikon muß in einer Form vorliegen, in der z.B. ein Morphologieprogramm die Daten des Lexikons verwenden kann. Einen Über3 [2], 4 [7], S. 54 S. 456 KAPITEL 2. DAS LEXIKON 7 blick über maschinenlesbare Lexika und ihren besonderen Probleme gibt [10]5 . Viel stärker als in traditionellen, auf Papier vorliegenden Lexika ist in der Computerlinguistik die formale Vollständigkeit und syntaktische Wohlgeformtheit der einzelnen Einträge des Lexikons eine grundlegende Voraussetzung. Deshalb gehen der Benutzung eines computergestützten Lexikons immer Schritte zur Überprüfung der Wohlgeformtheit der Einträge auf syntaktischer Ebene voraus, zum Teil begleitet von Plausibilitätsprüfungen für die bedeutungsorientierten Teile der Einträge. Diese Schritte übernehmen spezielle Programme. Sie übernehmen gleichzeitig mit der Konvertierung der Lexikondaten in ein internes Format die Aufgabe der Sortierung des Lexikons. Dazu muß ihnen ein Such- oder Sortierschlüssel vorgegeben werden. Meist wird eine Sortierung nur für programminterne Verarbeitungszwecke vorgenommen, um z.B. Suchvorgänge im Lexikon durch ein Programm zur morphologischen Analyse effizienter zu gestalten. Dadurch daß die Sortierung programmintern abläuft und die Erstellung des Lexikons nicht rückwirkend beeinflußt, können Lexikonbearbeiter auf eine Sortierung z.B. nach dem Alphabet verzichten, da diese in den anschließenden Bearbeitungsvorgängen automatisch erfolgt. Lexikonbearbeiter können ihr Lexikon deshalb so strukturieren, wie es ihnen z.B. aus linguistischen Erwägungen heraus sinnvoll erscheint. Die Einträge und ihr Format hängen vom Umfang der Daten ab, die mit ihnen repräsentiert werden sollen. Damit ist das Lexikon in hohem Maße abhängig von der z.B. zur morphologischen Analyse verwendeten linguistischen Theorie. Ein Programm, das zum Ziel hat, ein Lexikon zu verwalten, sollte aber möglichst wenig mit der jeweils verwendeten Grammatiktheorie verbunden sein. Die Trennung zwischen Lexikonverwaltung und Grammatiktheorie kann nur dann erfolgen, wenn die Lexikonverwaltung sich nicht um das Format des Lexikons bzw. seiner Einträge kümmern muß. In dieser Arbeit wurde versucht, die theorieabhängigen Aspekte des Lexikons soweit wie möglich von der Lexikonverwaltung trennen. Für die Lexikonverwaltung ist der einzelne Lexikoneintrag eine “black box”. Für die theorieabhängige Verarbeitung der Einträge sind andere, externe Programme verantwortlich. Im folgenden soll kurz in das Lexikonformat der Linksassoziativen Grammatik einführt werden, die den in der Computerlingustik Erlangen verwendeten Analysebzw. Generierungsprogrammen als theoretische Basis zugrundeliegt. 5 Kapitel “Existierende maschinenlesbare Lexika”, S. 73ff KAPITEL 2. DAS LEXIKON 8 2.2 Die LA-Grammatik und das Lexikon Die Linksassoziative Grammatik6 beschreibt einen Formalismus, der besonders zur Analyse und Generierung natürlicher Sprache geeignet ist. Die LA-Grammtik geht – wie andere Grammatiktheorien auch – davon aus, daß ein komplexer sprachlicher Ausdruck (eine Wortform, ein Satz) eine Kombination kleinster Einheiten der Sprache darstellt. Für die Morphologie sind diese kleinsten Einheiten Morpheme, für die Syntax sind es die Wortformen7 . In der LA-Grammatik erfolgt die Kombination der Einzelelemente strikt von links nach rechts. Der Name “linksassoziative Grammatik” erklärt sich daraus, daß ein neues (rechts vom schon analysierten Ausdruck stehendes Element) an alle bisher analysierten Elemente (links davon stehend) angehängt (konkateniert) wird. Die feststehende Ableitungsordnung von links nach rechts unterscheidet die LAGrammatik von anderen Grammatiktheorien. Die LA-Grammatik arbeitet nach dem Prinzip der Oberflächenkompositionalität. Teile eines komplexen Ausdrucks werden dann miteinander kombiniert, wenn die kategoriale Beschreibung der beteiligten Oberflächen die Kombination (Konkatenation) der Oberflächen zuläßt. LA-MORPH, die linksassoziative Beschreibung der Morphologie, benutzt ein Lexikon, das auf Morphem-Einträgen (Grundformeinträgen) basiert. Morpheme sind die kleinsten bedeutungstragenden Einheiten einer Sprache. Die gestaltlichen Varianten eines Morphems nennt man Allomorphe. Das Morphem ist ein Konzept auf der Ebene der Langue8 . In der ausgeübten Sprache (Ebene der Parole) treten dagegen nur Allomorphe auf. Die verschiedenen Allomorphe eines Morphems zeigen unterschiedliche Kombinationsmöglichkeiten mit anderen Morphemen und sind in den meisten Fällen komplementär-distributiv, z.B. die Pluralallomorphe e und er in Beine und Kinder, nicht aber *Beiner oder *Kinde. Detaillierte Beschreibungen der Begriffe Morphem und Allomorph finden sich z.B. in [22], S. 49f. oder in [16], S. 292ff. Das in natürlichen Sprachen vorzufindende strukturelle Prinzip der Bildung von Allomorphen aus Morphemen nennt man nach [16] Allomorphie-Prinzip. Aus den Grundformeinträgen9 werden über Allomorphregeln Allomorphe gene6 LA-Grammatik sind die im folgenden verwendeten Abkürzungen für den Begriff Linksassoziative Grammatik. 7 Wortformen sind grammatisch (phonologisch, morphologisch) analysierte Vorkommen eines Wortes, z.B. Hauses, Häuser. Das Wort ist eine semantische Einheit, z.B. Haus. 8 Zu den Begriffen Langue und Parole vgl. [9], S. 36ff 9 In dieser Arbeit wird der Terminus Grundformeintrag für die vom Bearbeiter zu edierenden Lexikoneinträge verwendet. Auch wenn diese Bezeichnung eine gewisse Nähe zur Grundform-Methode KAPITEL 2. DAS LEXIKON 9 riert. Nach der Allomorphgenerierung hat ein LA-MORPH-System alle aus dem Grundformlexikon generierbaren Allomorphe, die zur Kombination komplexer Ausdrücke benötigt werden, für die Laufzeit des Morphologieprogramms zur Verfügung. Diese Anwendung des Allomorphie-Prinzips in der LA-Grammatik nennt man Allomorph-Methode. Desweiteren gibt es die Grundform-Methode bei der erst zur Laufzeit des Morphologieprogramms die für die Kombination benötigten Stämme aus Grundformen gebildet werden. Dieses Vorgehen ist weniger effizient als die Allomorph-Methode. Dies steht im Gegensatz zur sogenannten Vollformen-Methode, die Lexika benutzt, in denen vollständig analysierte Wortform-Einträge gespeichert sind. In der LA-Grammatik wird ein Lexikoneintrag als ein geordnetes Tripel aus Oberfläche Kategorie und Stamm definiert. Die Oberfläche10 enthält die Zeichenkette der Wortform, die Kategorie (bestehend aus keinem, einem oder mehreren Kategorie-Segmenten) stellt die grammatische Beschreibung der Wortform (z.B. Valenzen und Präfixe eines Verbs, Beschreibung der Kombinatorik der Wortform im Satz) dar, und der Stamm trägt die Informationen zum Paradigma des Wortes. Gehören mehrere verschiedene Wortformen zu einem Wort (z.B. Suppletivformen11 wie bei sein, bin, ist, ...) werden sie durch dieselbe Zeichenkette im Stamm (in obigem Falle sein) “zusammengehalten”. In der LA-Grammatik wird ein Lexikon benutzt, dessen Einträge aus Morphemen besteht. Diese Morpheme werden z.B. durch MALAGA über Kombinationsregeln zu den zu analysierenden Wortformen zusammengesetzt. In den Vorgängerprojekten von MALAGA (NEWCAT12, LAMA13, MAGIC14 , suggeriert, wurde sie deswegen gewählt, weil der Begriff Morphemeinträge nicht zutreffen würde (es liegen ja Allomorphe vor) und der Begriff Allomorpheinträge schon für die durch den Allomorphgenerator aufbereiteten Grundformeinträge steht. 10 In Zukunft wird mit dem Begriff Oberfäche die Grundformoberfläche bezeichnet im Gegensatz z.B. zur Allomorphoberfläche. 11 Zum Begriff Suppletion vgl. [16], S. 296 12 [14] 13 [6] 14 [28] KAPITEL 2. DAS LEXIKON 10 MOSAIC15, LAP16) wurde ein direkt an diese Definition angelehntes Eintragsformat gewählt. Es stammt in seiner Form im wesentlichen aus dem NEWCAT-Parser, der in LISP implementiert ist: ("oberfläche" (KATEGORIESEGMENT-1 ... KATEGORIESEGMENT-n) STAMM) Bei diesem Format muß der Zugriff auf ein Element des Lexikoneintrags über die Position des gewünschten Eintragsteils erfolgen. Dadurch ist ein einfaches Extrahieren z.B. der Oberfläche möglich, indem die erste Position des Lexikoneintrags angesprungen wird und die Zeichenkette zwischen den Anführungszeichen kopiert wird. Dieser Vorgang ist wichtig, da die Oberfläche den Schlüssel des Lexikoneintrags darstellt (vgl. Abschnitt 2.5). In MALAGA wird ein anderes Lexikonformat verwendet, das nicht auf die im obigen beschriebenen festen Positionen der Eintragsteile festgelegt ist. Nichtsdestoweniger sind die beschriebenen Grundelemente vorhanden, wenn auch weniger offensichtlich. Das Vorhandensein dieser Elemente ist, wie beim Kapitel über die LDB zu lesen sein wird, grundlegend wichtig für die interne Struktur der LDB. 2.3 Das MALAGA-Format für Lexikoneinträge und Analysepfade In MALAGA wird ein Beschreibungsformat benutzt, das gleichermaßen für die Darstellung von Lexikoneinträgen als auch für die Darstellung der Ergebnisse einer morphologischen oder syntaktischen Analyse dienen kann. Ein Lexikoneintrag wird als sogenanntes Attribut-Werte-Paar dargestellt. Ein Attribut ist ein (vorher) festgelegter Bezeichner (z.B. LemOFl für die LemmaOberfläche), dem bestimmte Werte zugeordnet werden können. Bei LemOFl ist ein solcher Wert eine Zeichenkette (begrenzt von “ und ”). Andere mögliche Werttypen sind Kategoriesegmente, die vorab in einer eigenen Datei festgelegt werden müssen. Aber auch andere Attribut-Werte-Paare können einem Attribut als Wert zugeordnet werden (rekursive Struktur) sowie auch Listen bzw. Mengen von Werten. Eine feste Reihenfolge in Listen oder im Aufbau ist, außerhalb der Attribut15 [27] 16 [30], S. 16f KAPITEL 2. DAS LEXIKON 11 Werte-Struktur, nicht erforderlich. Jedoch bietet sich im Rahmen der Arbeitsdisziplin der Lexikonbearbeiter eine festgelegte Reihenfolge an, damit das Lexikon für die Bearbeiter leichter und weniger fehlerträchtig handzuhaben ist. Die folgende Abbildung zeigt einen typischen MALAGA-Lexikon-Eintrag: [ LemOFl: "folgen", WK: Verb, PII-Ge: Ge, PII-Aux_L: <PII-sein>, Val_L: <<Dat>>, PXL_L: <[PII-Ge: Ge, PII-Aux_L: <PII-haben>, Val_L: <<Akk>>, PxOFl: "bei", Sep: ja], [PII-Ge: Ge, PII-Aux_L: <PII-sein>, Val_L: <<DatRefl>>, PxOFl: "nach", Sep: ja], [PII-Ge: Ge, PII-Aux_L: <PII-sein>, PxOFl: "aufeinander", Sep: ja] >]; Will man auf die Werte zugreifen, die in einem Lexikoneintrag enthalten sind, so geschieht dies über das entsprechende Attribut. Man benötigt also eine Funktion, die zu einem bestimmten Attribut den Wert zurückgibt. Will man die Oberfläche eines Lexikoneintrags extrahieren, wird man diese Funktion mit dem Attribut LemOFl17 aufrufen und eine Zeichenkette (die Oberfläche) zurückerhalten. 2.4 Klartextlexikon und Laufzeitlexikon Bisher wurde nur das Prinzip der Allomorphie vorgestellt. Doch wie sieht das konkrete Vorgehen eines Lexikonbearbeiters aus18 ? Zuerst legt er eine Projektdatei an. In ihr werden alle betroffenen Dateien und deren zeitliche Abhängigkeiten voneinander eingetragen. Wichtige Dateien sind vor allem die Datei mit der Extension .lex, die die Namen aller zu verwendenden Lexikondateien enthält, die Allomorphregel-Datei (.all) und die Segmentedatei, die eine Auflistung aller im jeweiligen Projekt verwendeten Kategoriesegmente enthält. Diese Dateien liegen im ASCII19 -Format vor und können mit einem beliebigen 17 Die Namen der Attribute eines MALAGA-Eintrags werden vom jeweiligen Lexikonbearbeiter festgelegt. Sie sollen deshalb hier nicht ausführlich erklärt werden. 18 Die nun folgenden Verarbeitungsschritte werden ausführlich bei [3] beschrieben werden. 19 ASCII ist die Abkürzung von American Standard Code for Information Interchange. ASCII KAPITEL 2. DAS LEXIKON 12 Editorprogramm bearbeitet werden. Man könnte sie von daher im Gegensatz zu den aus ihnen generierten Dateien im programminternen Format Klartextdateien nennen. Zuerst wird der Segmentdatei-Compiler MALSEG aufgerufen, der eine Kodierung der Kategoriesegmente in ein internes Format durchführt. Als nächstes werden die Allomorphregeln mithilfe des Regelcompilers MALCOM in ein internes, von MALLEX lesbares Format umgewandelt. Auf der Basis der compilierten Kategorie-Segmente und der compilierten Allomorphregeln generiert dann das Programm MALLEX die Allomorphe zu den in der .lex-Datei angegebenen Grundformlexikoneinträgen. Ergebnis des gesamten Vorgangs sind die compilierten Kategoriesegmente und ein Allomorphlexikon im Binärformat, insofern kein Fehler bei den einzelnen Vorgängen auftritt. Sollte dieser Fall eintreten, müssen die jeweils davon abhängigen Schritte nach der Fehlerbehebung wiederholt werden. Die so erzeugten Datenstrukturen kann dann das MALAGA-Programm direkt verwenden, um seine Trie-Structure als Zugriffsstruktur auf das Allomorphlexikon aufzubauen. 2.5 Lexikoneinträge in Datenbanken Im Folgenden werden einige Begriffe aus dem Wortfeld der Datenbanken verwendet werden, die bisher noch nicht erklärt wurden. Dies soll zu einem späteren Zeitpunkt nachgeholt werden 20 . Es wird davon ausgegangen, daß die hier verwendeten Begriffe zumindest vage dem Leser bekannt sind. Dieses Vorgehen ist deswegen möglich, da an dieser Stelle der Aspekt des Lexikons wesentlich stärker betont wird als der der Datenbank. Nachdem die Notwendigkeit einer Datenbank zur Verwaltung des Lexikons bereits festgestellt wurde, stellt sich die Frage: Wie müssen Lexikoneinträge in einer Datenbank abgelegt werden? Zur Beantwortung dieser Frage muß man betrachten, wie Lexikoneinträge im allgemeinen in (gedruckten) Lexika repräsentiert werden. Die Lexikoneinträge sind in den meisten Fällen geordnet. In kleinen Lexika könnte beschreibt eine Tabelle, in der jedem Zeichen des Alphabets und einigen Sonderzeichen Zahlenwerte zugeordnet werden. ASCII ist ein sehr weit verbreiteter Standard zur Zeichenkodierung. 20 vgl. dazu das Kapitel 4 KAPITEL 2. DAS LEXIKON 13 auf diese Ordnung verzichtet werden. Ohne diese Ordnung sind Lexikoneinträge bei großen Lexika jedoch nur noch schwer und langsam auffindbar. Die Ordnung der Einträge richtet sich nach dem Zweck des Lexikons. Allen Ordungsweisen gemeinsam ist jedoch die Tatsache, daß ein bestimmter Teil des einzelnen Eintrags als repräsentativ für den Eintrag angenommen wird. Man nennt diesen Teil des Eintrags das Lemma. Aus der Sicht der Datenbank könnte man das Lemma auch als den Suchschlüssel bezeichnen, nach dem der Eintrag in die Datenbank eingefügt wird. Durch diesen Schlüssel kann man den Lexikoneintrag in der Datenbank wiederfinden. Dabei tritt ein schwerwiegendes Problem auf: um auf den Eintrag in einer Datenbank zugreifen zu können, muß der Schlüssel eindeutig sein. Diese Voraussetzung ist bei einem Lexikon in natürlicher Sprache nicht gegeben. In der natürlichen Sprache geschieht es häufig, daß sich mehrere Lexikoneinträge einen Schlüssel teilen. Als Beispiel soll das Wort “Gerade” dienen, dem drei Lexikoneinträge zugeordnet werden können: Gerade als Substantiv (die Gerade) gerade als Adjektiv (eine gerade Straße) gerade als Adverb (Er ist gerade weggegangen.) In traditionellen Lexika wird der Sortierschlüssel nur einmal, am Anfang des Eintrags angegeben und danach, im Eintrag zu diesem Schlüssel selbst, eine Untereinteilung z.B. durch Numerieren der einzelnen Lesarten vorgenommen. Betrachtet man aus dieser Sicht die Lexikoneinträge MALAGAs, so erkennt man unschwer, daß eine wesentliche Aufgabe der Lexikonverwaltung darin besteht, aus dem Lexikoneintrag den Schlüssel zu extrahieren. Dabei genügt es nicht, irgendeine oder die erste der durch “ ” markierten Zeichenketten zu extrahieren, da die Stellung der einzelnen Attribut-Werte-Paare in einem MALAGA-Lexikoneintrag frei ist und u.a. auch bei den Verben die Oberflächen der möglichen Präfixe im Lexikoneintrag stehen, die auch von “ ” umgebene Zeichenketten sind. Die Extraktion des Schlüssels eines MALAGA-Lexikoneintrags muß ähnlich wie die Sprachverarbeitung mit MALAGA selbst durch Auffinden des Schlüsselattributs vonstatten gehen. Auf die Schlüsselextraktion wird bei den Filterfunktionen (Abschnitt 6.2) und den linguistischen Unterscheidungen der Teildatenbanken (Abschnitt 3.1) näher eingegangen werden. Kapitel 3 Beschreibung der zu verarbeitenden Daten Nach den Überlegungen zu Lexikoneinträgen und den damit verbundenen Problemen werden nun die Eigenschaften der Daten, die in der LDB verwaltet werden sollen, und ihre Beziehungen untereinander betrachtet. 3.1 Die verschiedenen Datentypen Gemäß den vorher schon formulierten Anforderungen und den Erfordernissen bzw. Interessen eines Lexikonbearbeiters, muß für folgende Arten von Daten eine Repräsentation in der LDB gefunden werden: Grundformeinträge im Klartext, vom Benutzer definiert Allomorpheinträge im MALAGA-internen Binärformat, durch den Allomorphgenerator automatisch erzeugt Paradigmentabellen-Einträge, im LDB-internen Format Kommentar-Einträge, in komprimierter Form, zum Teil im Klartext Stamm-Einträge, zur Zeit nicht implementiert Auf das konkrete Format der einzelnen Einträge auf der Zeichenebene wird im Abschnitt über die Filterfunktionen 6.2 näher eingegangen werden. An dieser Stelle soll eine konzeptionelle Betrachtung der Daten stattfinden. 14 KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 15 Die Stammeinträge sollen in Zukunft die semantischen Informationen zu einem Lexikoneintrag enthalten. Ein genaues Format für die Darstellung dieser Informationen ist jedoch noch nicht entwickelt. In der LDB wurde für diese Informationen ein Modul vorgesehen, das zur Zeit noch keine Funktion erfüllt. Zu einem gegebenen Zeitpunkt ist an den entsprechenden Stellen im LDB-Programm die Behandlung dieser Daten einzufügen. In den weiteren Ausführungen sollen die Kommentareinträge vorerst unbetrachtet bleiben. Dies geschieht nicht, weil sie linguistisch nicht relevant wären. Es besteht im Gegenteil die Möglichkeit, über die Kommentare die Entwicklung des Lexikons zu verfolgen, Bemerkungen zu Problemen mit einem Lexikoneintrag anzufügen bzw. den Nachweis der Fundstelle in einem Korpus zu führen. Nichtsdestoweniger stehen die Kommentare außerhalb der im folgenden beschriebenen Generierungsbeziehung zwischen Grundformeinträgen und Allomorpheinträgen und werden deshalb getrennt behandelt. Den Ausgangspunkt aller Daten in der LDB stellen die Grundformeinträge dar. Sie sind das Material, mit dem ein Lexikonbearbeiter umgeht und in dem er das linguistische Wissen repräsentiert. Der Lexikonbearbeiter ist sich dabei immer des Zusammenhangs zwischen den Grundformeinträgen, den Allomorphregeln und den Kombinationsregeln1 bewußt. Aus diesen Daten wird in einem Generierungsvorgang automatisch das Allomorphlexikon erzeugt. Während dieser Generierung, die über die Allomorphregeln erfolgt, wird neben den Allomorphoberflächen und der compilierten kategorialen Beschreibung des Lexikoneintrags auch die Basiszeichenkette (bisher Stamm genannt) extrahiert. Wie schon vorher beschrieben, hält die Basis eines Lexikoneintrags alle Einzelallomorphe eines Wortes, also einer semantischen Einheit, zusammen. In den meisten MALAGA-Lexikoneinträgen wird man vergeblich ein Attribut “Basis” o.ä. suchen. Im Gegensatz z.B. zum LAP-Format für Lexikoneinträge2 , bei dem die Basis in Form des Stammeintrags immer explizit angegeben wird, ist die Basis im MALAGA-Format außer in besonderen Fällen nur implizit vorhanden. Dies beruht auf der Erkenntnis, daß bei den meisten Lexikoneinträgen die Basiszeichenkette während der Allomorphgenerierung regelhaft aus der Oberflächenzeichenkette und der Kategorie abgeleitet werden kann. Auf diese Weise kann die Redundanz von Zeichenketten im Grundformeintrag wesentlich gesenkt werden. Ausnahmen sind hier z.B. die Suppletiv-Formen. Bei diesen gibt es nur 1 Die Kombinationsregeln beschreiben die Konkatenation der Allomorphe zu fertig analysierten Wortformen. 2 vgl. Abschnitt 2.2 KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 16 sehr wenig oder keine Regelhaftigkeit3 zur Ableitung der einzelnen Wortformen voneinander, so daß die Allomorphregeln nicht greifen können. Zum Beispiel gibt es keine Möglichkeit aus der Oberfläche bess (zu besser) automatisch die Zugehörigkeit zum Paradigma des Wortes gut abzuleiten. Um dennoch die einzelnen Allomorphe miteinander verbinden zu können, wird in solchen Fällen die Basis (im Beispiel wäre das gut) explizit im Lexikoneintrag mitgeführt. Da sie als semantisch repräsentativ für das gesamte Formen-Paradigma eines Wortes angenommen wird, wird die Basis daher auch Paradigmeneintrag genannt. Das Beispiel zeigt die betreffenden Einträge von gut, besser und am besten, aus denen sich das Paradigma von gut zusammensetzt. Das Attribut GF enthält die Basiszeichenkette. [LemOFl: "gut", WK: Adjektiv, SB: <AdFl_adk, nein, nein>]; [LemOFl: "bess", GF: "gut", Fertig: ja, WK: Adjektiv, SB: < AdFl_k, nein, nein >]; [LemOFl: "be", GF: "gut", Fertig: ja, WK: Adjektiv, SB: < AdFl_s, nein, nein >]; 3.2 Die Beziehungen zwischen den verschiedenen Datentypen In welcher Beziehung stehen die drei Datentypen Grundformeinträge, Allomorpheinträge und Paradigmeneinträge zueinander? Die zentrale Rolle gebührt hierbei der Basis. Über die Basis lassen sich Allomorpheinträge und Grundformeinträge verbinden. Hierbei wird der Generierungsbe3 Zur Unterscheidung der Regularitätsgrade vgl. [6], S. 7, Abschnitt 2.3.1 KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 17 ziehung zwischen beiden Rechnung getragen. Wichtigstes Kriterium, das für die Basis als zentrales Element spricht, ist ihre Eindeutigkeit4 . Daß die Basis als einzige dieses Kriterium zu erfüllen scheint, ergibt sich daraus, daß z.B. bei Suppletivformen mehrere Grundformeinträge ein Paradigma formen können (z.B. bei sein, dessen Paradigma aus den Grundformeinträgen sein, bin, bist, ist, sind, ..., war, gewesen und den daraus generierten Allomorphen zusammengesetzt wird). Andererseits kommt es z.B. im Deutschen häufig vor, daß aus einem einzigen Grundformeintrag mehrere Allomorphe generiert werden, wie im Falle von gehen, zu dem die Allomorphe geh, ging und gang gebildet werden können. Dies ist eine grundlegende Eigenschaft der Allomorph-Methode. Da die Basis die semantische Komponente eines Lexikoneintrags darstellt5 , ist sie eindeutiger als die übrigen Komponenten des Lexikoneintrags, die “nur” grammatische (zum Teil sehr variable) Beschreibungen darstellen. Sowohl Grundformeinträge als auch Allomorpheinträge können durch Phänomene wie z.B. Homographie, Homophonie oder Zugehörigkeit zu einem der zahlenmäßig großen Flexionsbildungsmuster nicht eindeutig einem Wort zuzuordnen sein und scheiden daher als zentrales Ordnungskriterium aus. Beispiele sind die in der Oberfläche übereinstimmenden Grundformeinträge von be- und beste: [LemOFl: "be", WK: Präfix, Px: [ OFl: ja, Komb: <> ] ]; [LemOFl: "be", GF: "gut", Fertig: ja, WK: Adjektiv, SB: < AdFl_s, nein, nein >]; Der erste Eintrag ist anhand der (automatisch generierten) Basis leicht vom zweiten zu unterscheiden, der zu einer anderen Basis gehört. Die Basis bietet einen hohen Grad an Eindeutigkeit. Grundlage der Konzeption der LDB ist eine zentrale Zuordnungstabelle, die die Basis als Ordnungskriterium enthält. Jeder Basis werden durch Verweise Grundformeinträge und die dazugehörigen Allomorpheinträge zugeordnet. Diese Zuordnung wird durch die Regeln bei der Allomorphgenerierung festgelegt. Aus einem Grundformeintrag werden immer ein oder mehrere Allomorpheinträge generiert6 . 4 Die Probleme mit der Eindeutigkeit der Basis werden weiter unten in diesem Abschnitt darge- legt. 5 Es ist vorgesehen, daß das Basisattribut in Zukunft nicht mehr durch eine Zeichenkette, sondern durch einen komplexen Wert, in Form eines Verbundes im Lexikoneintrag steht. Darin soll semantische und pragmatische Information aufbewahrt werden. Nichtsdestoweniger wird diese komplexe Basis ein Attribut enthalten, das, wie die jetzige Basiszeichenkette, als stellvertretend für die semantische Komponente steht und somit als Semantikschlüssel fungiert. 6 Das Generieren von 0 Allomorphen zu einem Grundformeintrag ist in MALAGA nicht vorge- KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 18 Somit ergibt sich für das Verhältnis von Grundformeinträgen zu den aus ihnen generierten Allomorpheinträgen eine 1:n-Beziehung (wobei n > 0). Die Beziehung wird in der im folgenden Paradigmentabelle genannten zentralen Zuordnungstabelle abgebildet, und zwar aus einer Folge von Grundform-Allomorph-Tupeln. Für jeden Grundform-Eintrag gibt es in jedem Fall mindestens ein solches Tupel (dies folgt aus der Aussage, daß n > 0 sein muß). Ein einziges Grundform-AllomorphTupel gibt es dann, wenn das gesamte Paradigma durch einen einzigen Grundformeintrag beschrieben werden kann, und nur eine einzige Wortformoberfläche dem Paradigma angehört, wie bei den meisten Wörtern geschlossener Wortklassen, z.B. die Präposition über etc. Obwohl die Beziehung zwischen Grundformeintrag und Allomorpheinträgen eine 1:n-Beziehung ist, wird sie aus Verarbeitungsgründen auf eine n:n-Beziehung in den Paradigmeneinträgen abgebildet. Dies illustriert die Abbildung 3.1. Grundformeintrag [LemOFl:"g{eh}en", ...] Rückverweise Paradigmeneintrag Tupel 1 Tupel 2 Tupel 3 [BASE: "gehen", ...] Allomorpheintrag 1 [T_OF1: "geh", ...] Allomorpheintrag 2 [T_OF1: "gang", ...] Allomorpheintrag 3 [T_OF1: "ging", ...] Abbildung 3.1: Die Verweise zwischen den Datentypen am Beispiel des Wortes gehen Diese Form der Repräsentation wird nur intern vorgenommen; der Benutzer der Datenbank sieht bei der Ausgabe der Daten eine 1:n-Beziehung. Die Grundformeinträge wie auch die Allomorpheinträge benötigen einen ähnlichen Rückverweis auf den zu ihnen gehörenden Paradigmeneintrag. Auf diese Weise wird für jede Beziehung eine doppelte Verzeigerung angelegt (vgl. nochmals Abbildung 3.1), so daß man z.B. für einen bestimmten Grundformeintrag alle Allosehen. Dieser Fall tritt nur dann auf, wenn ein Fehler in den Allomorphregeln oder im Grundformlexikon vorliegt. KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 19 morphe suchen kann, oder umgekehrt den Grundformeintrag, aus dem ein gegebenes Allomorph generiert wurde. Der erste Umstand ist vor allem für eine morphologische Generierung oder die Überprüfung der Ergebnisse der Allomorphregeln interessant. Die eben beschriebene Konzeption wurde zuerst durch Fehler bei der morphologischen Generierung motiviert. Im morphologischen Analyse- und Generierungssystem LAP traten oft Übergenerierungsphänomene auf, die darauf zurückzuführen waren, daß auch paradigmenfremde Allomorphe zur Paradigmengenerierung herangezogen wurden. Dies lag an den Datenstrukturen in LAP und deren Aufbereitung. Als Beispiel soll die Generierung aller Wortformen des Wortes Dach (Hausdach) dienen. Dazu holte das LAP-System aus seinem Allomorphlexikon den passenden Allomorpheintrag hervor. Die Allomorphe waren nur auf einfache Weise im Zusammenhang mit den zugehörigen Paradigmeneinträgen verbunden. Also fand das LAP-System neben dem Allomorph dach von Dach, das Allomorph dach zu denken (dachte). Außerdem wurden die Allomorphe däch zu Dach (Dächer), däch zu denken (dächte) und denk zu denken gefunden. Für alle diese Allomorphe wurden Flexionsformen generiert. Ergebnis war ein Paradigma von Dach, das zufällig noch das Paradigma von denken enthielt. Dieses Vorgehen ist offensichtlich falsch. Es kann dadurch verhindert werden, daß beim Allomorphgenerierungsprozeß über den Paradigmeneintrag in der Paradigmentabelle durch Verweise die Generierungsbeziehung zwischen Grundformeinträgen und Allomorpheinträgen festgehalten wird. 3.3 Einflüsse von Homonymie und Polysemie auf die Lexikoneintragsstruktur Im Verlauf dieser Arbeit traten Probleme mit der Verarbeitung der Basis auf, die darin begründet waren, daß auch die Basiszeichenkette in einigen Fällen nicht als eindeutiger Schlüssel dienen kann. Dies tritt dann auf, wenn es zu einem Lexikoneintrag polyseme bzw. homonyme Einträge gibt. Nach Bußmann liegt Polysemie im Gegensatz zu Homonymie dann vor, “wenn ein Ausdruck zwei oder mehr Bedeutungen aufweist, die allesamt etwas gemeinsam haben und sich meist aus einer Grundbe- KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 20 deutung ableiten lassen. Der Unterschied zur Homonymie liegt nach traditioneller Auffassung darin, daß bei letzterer die verschiedenen Bedeutungen auf verschiedene etymologische Wurzeln zurückgeführt werden und und man somit von verschiedenen Wörtern reden muß, während die Bedeutungsvarianten polysemer Ausdrücke auf die gleichen Wurzeln zurückgehen.”7 Die Grenzen für die Unterscheidung zwischen Homonymie und Polysemie sind schwer zu ziehen. Dieses Problem ist in der Linguistik vieldiskutiert. Dabei legen die Autoren jeweils ihr Augenmerk auf bestimmte Aspekte des Polysemie/Homonymieproblems. Wie noch zu sehen sein wird, scheint es im vorliegenden Fall gar nicht angebracht zu sein, diese Unterscheidung vorzunehmen. Für die LDB ist vielmehr das Phänomen wichtig, das zu dieser Unterscheidung führt. Durch die Notwendigkeit, die Basiszeichenkette in der LDB als eindeutigen Suchschlüssel zu verwenden, ist auch die Notwendigkeit einer eindeutigen Unterscheidung zwischen verschiedenen Wörtern mit gleicher Basiszeichenkette gegeben. Das Problem der Nichteindeutigkeit der Basis wurde schon kurz bei den speziellen Problemen angerissen, die die Repräsentation eines Lexikons in einer Datenbank aufwirft. Dem dort angeführten Beispiel gerade stehen noch mehrere andere zur Seite, von denen nur eine kleine Anzahl zur Verdeutlichung angeführt werden soll: reifen (Verb), der Reifen (Nomen); braten (Verb), der Braten (Nomen); der Moment (Zeitpunkt), das Moment (Beweggrund); der Ekel (Gefühl), das Ekel (Widerling); der Schimmel (Pilz), der Schimmel (Pferd), die Bank (Sitzgelegenheit), die Bank (Geldinstitut), usw. Dabei läßt sich feststellen, daß die Mehrzahl dieser Wörter einem bestimmten Konfliktmuster8 folgt. Diese Muster sind der Nomen-Nomen-Konflikt, der VerbNomen-Konflikt und der Verb-Adjektiv-Konflikt.9 Insgesamt sind im derzeitigen Lexikon mit ca. 21000 Einträgen schätzungsweise 50 bis 100 solcher offensicht7 [7], S. 593 8 Als Konflikt wird hier die Tatsache bezeichnet, daß die Basiszeichenketten zweier Einträge iden- tisch sind, und daher ein Konflikt bei der Entscheidung vorliegt, welches der beiden paradigmenfremd ist. 9 Sicher werden beim Arbeiten am Lexikon noch andere Konflikte erkannt werden. KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 21 lichen Fälle enthalten.10 Eine nähere Betrachtung des Lexikons auf diesen Aspekt hin muß Teil der zukünftigen Lexikonarbeit sein. Allen Beispielen ist gemeinsam, daß mehreren Wörtern (= semantischen Einheiten) durch die Allomorphgenerierung dieselbe Basis zugeordnet wird. Man könnte annehmen, daß diese Einträge sich dann zumindest in ihrer Kategorisierung unterscheiden würden. Dies ist aber nicht der Fall. Widerlegt wird dies z.B. durch die Singularallomorphe der Wörter Bank (s.o.). Zwar unterscheiden sich die Pluralallomorphe sowohl in ihrer Oberfläche (die Bänke vs. die Banken) als auch in ihrer Kategorisierung. Die Singularallomorphe aber sind sowohl in der Oberfläche als auch in der Kategorie identisch. Derartige Fälle würden in der LDB alle demselben Wort zugeordnet werden. Würde man an die Lexikondatenbank eine Anfrage richten, die alle Allomorphe z.B. zum Wort Braten zurückliefern sollte, würde sie in diesem Fall die Allomorphe braten, brat, brät und briet liefern, die alle die gleiche Basiszeichenkette haben. Hier liegt also eine ähnliche Situation wie zuvor in LAP vor. Dieses Problem trat in allen MALAGA-Vorgängerprogrammen auf. In der bisherigen Form der morphologischen und syntaktischen Analyse trat die semantische Komponente eher in den Hintergrund. Deshalb bestand für die aufgeführten Problemfälle kein akuter Lösungsbedarf. 3.4 Berücksichtigung der Polysemie und Homonymie in der LDB Mit der Konzipierung der LDB wurde dem beschriebenen Problem homonymer bzw. polysemer Wörter Rechnung getragen. In Fällen wie den oben beschriebenen ist es notwendig, ein zusätzliches Kriterium zur Unterscheidung verschiedener Wörter mit gleichen Basisformen einzuführen. Es liegt nahe, dieses Kriterium im Lexikoneintrag als zusätzliches Attribut einzufügen. Dieses Attribut wird im folgenden mit SF-Attribut11 (SF) bezeichnet werden. Es ist aus Gründen der Übersichtlichkeit und der Platzeffizienz nicht sinnvoll, bei jedem Lexikoneintrag ein SF-Attribut einzufügen, das im Normalfall entweder leer wäre oder mit der Basis zusammenfallen würde. Die Problemstellung ist die gleiche wie für das Basisattribut z.B. bei Suppletivformen. 10 Diese Zahl ist nur ein Eindruck der bei einer kurzen Sichtung des Lexikons gewonnen wurde. Nähere quantitative Untersuchungen konnten im Rahmen dieser Arbeit nicht durchgeführt werden. 11 SF ist die Abkürzung für “Semantic Feature” KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 22 Deshalb wird das SF-Attribut ebenso wie das Basisattribut nur dann eingetragen, wenn eine Unterscheidung durch Homonymie bzw. Polysemie mehrerer Lexikoneinträge notwendig wird. Die LDB unterscheidet gleiche Basisformen nach diesem zusätzlichen SF-Attribut. Das SF-Attribut wird in einer Filterfunktion zusammen mit dem Grundformschlüssel aus dem Grundformeintrag extrahiert. Zusammenfassend läßt sich feststellen, daß mindestens vier verschiedene Einheiten (Module) einzurichten sind, um die Grundform-, die Allomorph-, die Paradigmen- und die Kommentareinträge zu speichern. Die Grundformeinträge sind mit den Allomorpheinträgen über die Paradigmeneinträge verzeigert, wie in Abbildung 3.1 zu sehen ist. Eine zusätzliche Verzeigerung zwischen Kommentaren und Grundformeinträgen ist nicht notwendig, da sie implizit vorhanden ist. Kommentare sind immer auf einen bestimmten Eintrag bezogen. Das bedeutet, daß ein Kommentareintrag zu einem Lexikoneintrag im Kommentarmodul unter demselben Schlüssel abgelegt ist wie der Grundformeintrag selbst. Das Kommentarmodul und das Grundformlexikon sind die einzigen Datenbereiche, in denen der Lexikonbearbeiter eingreifen und Änderungen vornehmen kann. Allomorphlexikon und Paradigmentabelle werden automatisch aus dem Grundformlexikon generiert und stehen somit in direkter Abhängigkeit von diesem. Änderungen durch den Lexikonbearbeiter müssen für diese Datenbereiche untersagt werden, da dies zu logischen Inkonsistenzen in der LDB führen würde. Zum Beispiel könnte ein Lexikonbearbeiter die Allomorphe nebst ihrer grammatischen Beschreibung unter Umgehung der Allomorphregeln und der Allomorphgenerierung direkt in das Allomorphlexikon eintragen. Dies darf nicht zugelassen werden, da er auf diese Weise die Allomorph-Methode verletzt hätte, und zum anderen die Verweise zwischen den Datengruppen nicht mehr regelhaft durch eine linguistisch gesteuerte Generierung, sondern durch die Willkür des Lexikonbearbeiters entstanden wären. Die Beziehungen zwischen den einzelnen Daten auf der konzeptionellen Ebene12 werden in Abbildung 3.2 veranschaulicht13 . In der Abbildung sind Grundform, Allomorph und Basis als Grundeinheiten (rechteckige Kästen) mit jeweils mehreren Attributen (ovale Objekte) gezeigt . Unter den Attributen gibt es jeweils ein besonderes (in der Abbildung unterstriche12 vgl. Abschnitt 4.2 13 Die Art der Darstellung geschieht übereinstimmend mit [11], S. 54ff. Dort wird auch die Bedeutung der Symbole der verwendeten Notation ausführlich erklärt. KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN 23 nes), welches der Suchschlüssel der Grundeinheit ist. In den Rauten wird die Beziehung zwischen den Einheiten angegeben. Die Verbindung zwischen Grundform und Kommentar wird mit doppelten Linien dargestellt, um die enge Bindung der beiden Einheiten durch die Benutzung eines gemeinsamen Schlüsselattributs auszudrücken14 . Die Darstellung der Beziehung zwischen Allomorphen und der Basis scheint im Widerspruch zur Tatsache zu stehen, daß die Basiszeichenkette bei der Allomorphgenerierung, also eigentlich in der Beziehung “generiert” extrahiert wird. In der Abbildung gibt es jedoch eine Extraktionsbeziehung zwischen Allomorpheinträgen und Basiszeichenkette, die scheinbar nirgends beim realen Generierungsvorgang stattzufinden scheint. Hier täuscht der erste Blick. Im MALAGA-System ist die Extraktion der Basis im Allomorphgenerator integriert, wird aber hier der Klarheit wegen getrennt dargestellt. Dasselbe gilt für die Schlüsselextraktion aus dem Grundformlexikon, die zugleich auch das SF-Attribut extrahiert, wenn es in einem Grundformeintrag angegeben wurde. 14 [11] ship). beschreiben eine solche Verbindung als schwache Verbindung (engl. weak entity relation- KAPITEL 3. BESCHREIBUNG DER ZU VERARBEITENDEN DATEN GrundformEintrag 24 Basiszeichenkette SF-Attribut Kategorie Oberfläche Allo-Oberfläche 1 GENERIERT N GRUNDFORM ALLOMORPH M N ORDNET_ZU 1 1 1 BASIS BESCHREIBT N EXTRAHIERT 1 Basiszeichenkette SF-Attribut KOMMENTAR Oberfläche Operation Benutzer-Daten KommentarZeichenkette Abbildung 3.2: Darstellung der Datentypen in der LDB nach dem EntityRelationship-Modell Kapitel 4 Datenbanken In diesem Kapitel wird zunächst darauf eingegangen, was eine Datenbank ist, welche Eigenschaften Datenbanken aufweisen, welche Daten sie verwalten können und wie sie die Beziehungen der Daten untereinander darstellen können. Das Modell der Netzwerkdatenbank wird näher betrachtet, weil die LDB diesem Datenbankmodell folgt. 4.1 Was ist eine Datenbank? Auf diese Frage gibt der Informatik-DUDEN folgende Definition als Antwort: Eine Datenbank ist ein “System zur Beschreibung, Speicherung und Wiedergewinnung von umfangreichen Datenmengen, die von mehreren Anwendungsprogrammen benutzt werden. Es besteht aus der Datenbasis, in der die Daten abgelegt werden, und den Verwaltungsprogrammen (Datenbanksoftware, Datenbankmanagementsystem), die die Daten [...] abspeichern, auffinden oder weitere Operationen mit den Daten durchführen. [...] Datenbanken sind von zentraler Bedeutung für die Datenverarbeitung.”1 Es gilt demnach, die Datenbank als abstrakte Sammlung von Daten einerseits von den sie verwaltenden Programmen (das Datenbankmanagementsystem, DBMS) 1 [12], S. 137 25 KAPITEL 4. DATENBANKEN 26 andererseits zu unterscheiden. Die unabhängige Betrachtung der Daten und der sie verarbeitenden Programme ist eine vergleichsweise junge Sichtweise. Deshalb soll kurz auf die Verhältnisse, unter denen Daten verarbeitet wurden und die zur Einführung der verschiedenen Datenbankkonzepte geführt haben, eingegangen werden. Traditionell werden Daten in Dateien gespeichert. Die Daten müssen dabei je nach Anwendungszweck in verschiedenen Formaten abgelegt werden, und zwar in Abhängigkeit davon, in welchem Format die verarbeitenden Programme die Daten bei der Datenverarbeitung erwarten. Wie man sich leicht vorstellen kann, führt dies zu einer großen Anzahl unterschiedlicher Datenformate. Die Nachteile dieser Art der Datenverwahrung liegen auf der Hand: Redundanz: Daten sind mehrfach (in unterschiedlichem Format) vorhanden. Inkonsistenz: dadurch, daß dieselben Daten an mehreren verschiedenen und unverbundenen Stellen liegen können, ist die Konsistenz der Daten nur sehr schwer aufrecht zu erhalten. Veränderungen im Datenformat machten ein Umstellen (Modifikation oder sogar Neuprogrammierung) der sie verarbeitenden Programme zwingend notwendig, um weiterhin Zugang zu den Daten zu erhalten Gemeinsamer Zugriff mehrerer Benutzer ist nur eingeschränkt möglich. Papazoglou und Valder konstatieren, daß dateiverarbeitende Systeme ihre Aufgaben nur mit erheblichen Problemen erfüllen konnten und daß “ihre charakteristischen Probleme [...] zur Entwicklung der Datenbanksysteme [führten].”2 Die grundlegende Zielsetzung aller Datenbanken ist: Vermeidung von Datenredundanz Zugriff mehrerer Benutzer auf gemeinsame Daten Ausschluß von Dateninkonsistenzen 2 [24], S. 13 KAPITEL 4. DATENBANKEN 27 Wahrung der Integrität der Daten Vereinfachter Zugriff durch Programme aufgrund definierter Schnittstellen zur Datenbank Diese Forderungen werden durch das Aufbauen eines leistungsfähigen Datenbankmanagementsystems erfüllt, das sowohl Hilfsmittel zur Definition logischer Sichtweisen auf die Daten (Datenbankschemata) bietet als auch die entsprechenden Verarbeitungswerkzeuge zur Verfügung stellt. Bereits hier ist ersichtlich, daß ein wesentliches Merkmal von Datenbanken darin liegt, daß die logische Behandlung der Daten von der physikalischen strikt getrennt wird. Diesen Aspekt nennt man Datenunabhängigkeit. 4.2 Ebenen der Datenbeschreibung Bei der Sichtweise auf die Daten der Datenbank unterscheidet man drei Ebenen der Datenrepräsentation: die interne Ebene, die die physikalischen Aspekte der Datenspeicherung und des Datenzugriffs abdeckt, die konzeptionelle Ebene, die “eine abstrakte und allgemeine Beschreibung des Teils der Welt [ist], der durch die Daten einer Datenbank repräsentiert werden soll.”3 und die externe Ebene, die dem Datenbankbenutzer den für ihn bestimmten Ausschnitt aus der Datenbank und eine bestimmte Sichtweise der Daten gewährt. Über die Möglichkeiten der Datenstrukturierung in den verschiedenen Datenmodellen wird in den folgenden Abschnitten ausführlich gesprochen werden. 4.3 Datenmodelle Es gibt verschiedene Typen von Datenbanken, die auf verschiedenen Datenmodellen beruhen. Diese eignen sich je nach Typ zur Lösung unterschiedlicher Problemstellungen, i.e. der Art der Daten. Hier stellt sich die Frage, welcher Typ von 3 [24], S. 15 KAPITEL 4. DATENBANKEN 28 Datenbank den Anforderungen für die Darstellung der Daten und die Zugriffe auf die Daten in der LDB am besten gerecht wird. In der Literatur werden, ausgehend von der Art der Datenrepräsentation, zwei grundsätzliche Datenbanktypen unterschieden: datensatz-orientierte und objekt-orientierte. Die traditionellen Datenbanken sind datensatz-orientiert, auch die LDB. Die Literatur4 steht objekt-orientierten Ansätzen verhalten gegenüber. Dies wird mit ungenügender logischer Beschreibbarkeit der objekt-orientierten Datenstrukturen begründet. Auf sie soll nicht näher eingegangen werden. Die kleinste in einer Datenbank betrachtete Einheit bestimmt die Granularität der Datenbank. Bei datensatz-orientierten Datenbanken ist die kleinste Einheit der Datensatz. Das DBMS muß Funktionen zum Manipulieren dieser Einheiten zur Verfügung stellen. Auf größere Einheiten kann u.U. nur über kombinierte Funktionen zugegriffen werden. Die datensatz-orientierten Datenbanken werden wiederum untergliedert in relationale Datenbanken, hierarchische Datenbanken und Netzwerkdatenbanken. Im Hinblick auf die Eignung eines bestimmten Datenbanktyps für die LDB sollen diese drei Arten von Datenbanken kurz beleuchtet werden. Relationale Datenbanken sind die zur Zeit am meisten verwendete Art von Datenbank. Implementierungen relationaler Datenbanken sind zum Beispiel Oracle, Ingres, Postgres, Requiem, u.a. [24] sprechen ihnen die Eigenschaft zu, daß “Der Benutzer [...] eine relationale Datenbank als Menge von Tabellen auffassen [kann], denen jeweils ein eindeutiger Name zugeordnet ist. [...] Jede Tabelle setzt sich aus einem Tabellenkopf und einem Tabellenrumpf zusammen. Der Tabellenkopf besteht aus einer festen Anzahl von Spalten, die man im allgemeinen als Attribute bezeichnet. 4 z.B. [24], S. 18 KAPITEL 4. DATENBANKEN 29 Der Tabellenrumpf dagegen enthält eine variable Anzahl von Zeilen, Tupel genannt. Es gibt eine enge Beziehung zwischen dem Begriff der Tabelle und dem mathematischen Konzept einer Relation, von der die relationale Datenbank ihren Namen hat.”5 Relationale Datenbanken eignen sich aufgrund ihrer Tabellenstruktur besonders gut für die Repräsentation von Daten, die untereinander eine 1:1 Beziehung haben. Sie verfügen über sehr mächtige Beschreibungsmittel zur Darstellung der Daten auf der konzeptuellen Ebene und zum Zugriff auf die Daten, z.B. umfangreiche Datenbankabfragesprachen (engl. query language). In hierarchischen Datenbanken werden die Daten und ihre Beziehungen untereinander als Bäume dargestellt. Sie eignen sich besonders zur Modellierung von Daten, deren Abhängigkeiten untereinander sich als Dominanzverhältnis auffassen läßt. Damit werden hierarchische Datenbanken in Bereichen verwendet, die Taxonomien darstellen müssen wie z. B. biologische Beschreibungen von Pflanzenoder Tierstammbäumen oder genealogische Sachverhalte6 Beispiele für hierarchische Datenbanken sind MARS VI, IMS oder MRI System 2000. Die oben beschriebenen Analysen zur Art der Daten und die Beziehungen zwischen den einzelnen Arten von zu repräsentierenden Daten legen die Vermutung nahe, daß die LDB ihrer Struktur nach am besten durch den Einsatz des Netzwerkdatenbankmodells realisiert werden kann, welches im folgenden näher beleuchtet werden soll. 4.4 Netzwerkdatenbanken Im Netzwerkdatenbank-Modell werden die Daten und ihre Beziehungen als verallgemeinerte Graphen repräsentiert. Dabei bilden diese Graphen netzartige Strukturen aus. 4.4.1 Verbunde Für die Modellierung der Daten in einer Netzwerkdatenbank (NDB) gibt es zwei Datenstrukturen. Die einen transportieren und repräsentieren die Daten und heißen 5 [24], S. 44 diese sich als echte Bäume und nicht als allgemeine Graphen darstellen lassen. 6 Wenn KAPITEL 4. DATENBANKEN 30 Verbunde (engl. records). Die anderen stellen die Beziehungen zwischen Verbunden her und bauen dadurch die Netzstruktur auf. Diese heißen Mengen (engl. sets). Verbunde sind typisiert. Ihr Typ richtet sich nach den Elementen, die in ihnen repräsentiert werden sollen. Den Elementen eines Verbunds (auch Attribute genannt) werden ein Name und ein die Daten beschreibendes Datenformat zugeordnet. Neben atomaren Elementen sind in Netzwerkdatenbankverbunden auch Felder (engl. vectors) und verschachtelte Gruppen (engl. repeating groups) als Datentypen für Elemente zugelassen. Die folgende Abbildung (4.1) zeigt einen der in der LDB verwendeten Verbunde, die überlicherweise in Form eines Bachman-Diagramms vorliegen, und zwar den für den Grundformeintrag: Grundform Oberfläche GrundformEintrag SF-Attribut Abbildung 4.1: Exemplarischer Verbund der LDB, hier ein Grundformeintrag Der Verbund Grundform hat die Grundformeintrag und SF-Attribut. Elemente Oberfläche, Neben diesen als aktuell bezeichneten Verbundtypen (engl. actual record) gibt es virtuelle oder abgeleitete (engl. derived) Verbunde. Im Gegensatz zu den aktuellen, in denen die Daten selbst liegen, stellen die virtuellen Verbunde nur einen Ansprechpunkt dar. Wird dieser Punkt von außen angesprochen, wird z.B. eine Rechenvorschrift ausgeführt, die an diesen Typ Verbund geknüpft ist, um zum jeweiligen Zeitpunkt Daten aus anderen Elementen des Verbunds zu dem virtuellen Verbundwert zu verknüpfen. Nach der Abfrage geht dieser Wert wieder verloren. 4.4.2 Mengen Um die zum Teil vielfältigen Beziehungen zwischen den einzelnen Verbundtypen festzuhalten, wird die zweite grundlegende Datenstruktur, die Menge, benötigt. Mengen beschreiben strukturell bedingt Beziehungen des Typs 1:n. Der Grund dafür wird erkennbar, wenn man die Struktur einer Menge betrachtet, die aus drei Teilen besteht: KAPITEL 4. DATENBANKEN 31 der Name für den Mengentyp der Verbundtyp, der den Besitzer des Mengentyps (engl. owner record) darstellt und der Verbundtyp der Elemente einer Menge (member record). Die Menge mit dem Namen generiert der LDB wird in Abbildung 4.2 veranschaulicht. Grundform Oberfläche GrundformEintrag SF-Attribut generiert Allomorph Oberfläche Kategorie Basis Abbildung 4.2: Exemplarische Menge der LDB Deutlich wird hier die in Abbildung 3.2 gezeigte 1:n-Beziehung zwischen Grundformeintrag und Allomorpheinträgen ausgedrückt: der Besitzer der Menge ist der Verbundtyp Grundform. Die Elemente sind Verbunde vom Typ Allomorph, der Name der Menge ist generiert7. Die dargestellte Menge ist nur eine abstrakte Vorlage für eine reale Instanz der Menge (engl. set occurrence oder set instance) in einer gerade aktiven Datenbank. Die Instanz einer Menge beinhaltet einen Besitzer-Verbund (oder einen Verweis auf ein solchen) und keinen, einen oder mehrere Element-Verbunde (oder Verweise auf solche). Die implizite 1:n-Beziehung ist dadurch gegeben, daß jeder ElementVerbund nur in einer Instanz einer Menge enthalten sein kann, aber eine Menge mehrere Element-Verbunde desselben Typs enthalten kann. 7 Die Bezeichnungen entsprechen denen in Abbildung 3.2 KAPITEL 4. DATENBANKEN 32 Der hier verwendete Begriff der Menge fällt nur zu einem Teil mit dem mathematischen Mengenbegriff zusammen. So unterscheidet sie die Eigenschaft, daß bei Mengen in NDBs die Reihenfolge der Elemente (i.e. der Element-Verbunde) nicht frei ist, im Gegensatz zu Mengen in der Mathematik, bei denen die Reihenfolge unerheblich ist. Hinzukommt, daß in den hier vorgestellten Mengen der Besitzer der Menge als ausgezeichnetes Element nicht gleich wie die anderen Mengenelemente behandelt wird. 4.4.3 Anwendung von Mengen und Verbunden Durch das bisher beschriebene läßt sich ersehen, daß in einer NDB sehr komplexe Beziehungsstrukturen aufgebaut werden können. Die Beziehungen, die vom Datenbankdesigner festgelegt und von den Datenbankbenutzer mit Daten ausgefüllt werden, werden beim Einfügen eines Eintrags in die Datenbank aufgebaut. Das Verhalten der Datenbank beim Einfügen kann mit Hilfe von Einfügeoptionen (engl. insertion options) beeinflußt werden: entweder werden die Beziehungen automatisch oder manuell aufgebaut. Für das automatische Herstellen der benötigten Verbindungen müssen dem DBMS Vorschriften mitgegeben werden. Das manuelle Einfügen verlangt vom Datenbankbenutzer zum Teil umfangreiche Kenntnis der Datenbankstrukturen, damit er die Verbindungen richtig herstellen kann. Wenn eine Menge aufgelöst wird (z.B. durch Löschen des Besitzer-Verbunds), müssen die sogenannten Aufbewahrungsoptionen8 beachtet werden. Sie bestimmen, ob ein bestimmter Verbund-Typ in der Datenbank als “freier”, ungebundener Verbund vorkommen darf oder nicht. Aus diesen Optionen lassen sich mehrere Kombinationen konstruieren, von denen aber einige logisch nicht sinnvoll sind. Neben den angeführten Optionen gibt es noch solche, die die Sortierreihenfolge der Verbunde beim Einfügen eines neuen Verbunds in eine Menge festlegen. Für die Sortierung gibt es vier Möglichkeiten. Es sind dies die Sortierung nach einem Schlüsselfeld: Ein ausgezeichnetes Attribut des Verbunds dient als Sortierschlüssel. 8 Dies ist eine Übersetzung des englischen Begriffs retention options; [31] übersetzt retention u.a. mit Gedächtnis, Beibehaltung, Bewahrung KAPITEL 4. DATENBANKEN 33 der Systemfestlegung: Im DBMS wird eine bestimmte Sortierreihenfolge als Voreinstellung benutzt. erster oder letzter Position: Neue Einträge werden entweder vor allen anderen oder nach allen anderen eingefügt. der aktuellen Position in der Menge: Ein neuer Eintrag wird vor oder nach dem aktuellen Verbund eingefügt. In NDBs gibt es mehrere Spezialtypen von Mengen (z.B. Mehrtypenmengen oder rekursive Mengen), von denen hier nur noch die Mengen beschrieben werden sollen, deren Besitzer das DBMS (engl. system owned record) ist. Bei diesen handelt es sich um den Ausgangspunkt jeder Operation in einer NDB. Zudem kann über die geeignete Definition von Mengen, deren Besitzer das DBMS ist, dem Benutzer der Zugriff auf die Daten auf unterschiedliche Art und Weise ermöglicht werden, je nachdem welcher Mengentyp als Einstiegspunkt in die NDB gewählt wird. Bevor die verschiedenen Operationen zum Zugriff auf die NDB erklärt werden, sollen die Möglichkeiten und Einschränkungen zur Darstellung der Zuordnungen in einer NDB aufgeführt werden. KAPITEL 4. DATENBANKEN 34 4.4.4 Beschreibung der Beziehungen zwischen Verbunden 4.4.4.1 D IE B EZIEHUNG 1:1 Die 1:1-Beziehung läßt sich als eine Einschränkung der 1:n-Beziehung auffassen. Da innerhalb der Mengen keine Möglichkeit besteht, die Anzahl der ElementVerbunde zu kontrollieren, ist es Aufgabe des Datenbankprogrammierers, ein Einfügen von mehr als einem Element in eine Menge zu verhindern, die eine 1:1Beziehung bezeichnet und schon ein Element enthält. 4.4.4.2 D IE B EZIEHUNG M:N Sollen in einer NDB zwei Verbunde über eine m:n-Beziehung verbunden werden, so ist dies nicht direkt möglich. Die den Mengen einer NDB implizite, strukturell bedingte 1:n-Relation beschränkt die direkte Verbindung beider Verbunde9 . Deshalb muß ein dritter, sogenannter Verbindungsverbund (engl. linking record) eingeführt werden, über den diese Beziehung abgebildet werden kann. 4.4.4.3 D IE B EZIEHUNG 1: N Die 1:n-Beziehung wurde schon als strukturelles Merkmal der Mengen in NDBs erklärt. 4.4.5 Weitere Datenstrukturen in Netzwerkdatenbanken Für das Arbeiten der Benutzer mit einer NDB werden bestimmte Datenstrukturen und Datenbereiche reserviert. Diese sind im einzelnen der Benutzerbereich (engl. user work area): Im Benutzerbereich werden die dem Benutzer zuzuschickenden bzw. die vom Benutzer erhaltenen Daten, die den einzelnen Zugriffsvorgang betreffen, in Programmvariablen des DBMS gespeichert. Diese Daten verlieren ihre Gültigkeit, wenn ein kompletter Zugriff (vgl. Begriff der Transaktion, 4.5.1) abgeschlossen ist oder ein anderer Benutzer auf die Datenbank zugreift. Navigationsindikatoren (engl. currency indicators): Mit ihnen wird ein Verweis auf den gerade benutzten oder gefundenen Verbund bzw. die Mengeninstanz festgehalten. Ebenso kann der Typ des letzten 9 vgl. [11], S. 294f KAPITEL 4. DATENBANKEN 35 Verbunds oder der letzten Menge gespeichert werden. Die Navigationsindikatoren sollen bei mehreren aufeinanderfolgenden Datenbankzugriffen diese beschleunigen, indem das DBMS nicht jedesmal alle Pfade bis zum gesuchten Datum abgehen muß, sondern direkt an der letzten Fundstelle mit der Suche beginnen kann. Zustandsanzeiger (engl. status indicators): Sie zeigen Erfolg oder Mißerfolg der letzten Operation(en) in der Datenbank an. Beim Mißerfolg kann detailliertere Information über Art des Fehlers u.ä. vermerkt werden. 4.4.6 Datenbanksprachen in Netzwerkdatenbanken Für die Nutzung einer NDB werden zwei verschiedene Sprachen verwendet: die Datendefinitionssprache und die Datenzugriffssprache. Mit der Datendefinitionssprache werden dem DBMS die verschiedenen Verbundund Mengentypen einschließlich ihrer möglichen Werte bekannt gemacht. Die Datendefinitionssprache ist spezifisch für ein bestimmtes Datenschema. In NDBs wird sie meist direkt in Datenstrukturen der Programmiersprache des DBMS übersetzt. In der LDB wurde auf diese Stufe der Datenbeschreibung verzichtet. Die Beziehungen zwischen den einzelnen Komponenten sind bekannt, formal beschrieben und durch die Anforderungen der LAG an eine LDB festgelegt, so daß auf die Flexibilität, die eine Datendefinitionssprache dem Datenbankdesigner bietet, verzichtet werden kann. Gewisse Designfreiheiten sind für eine mögliche Änderung der Beziehungsstrukturen der LDB dennoch durch die Verwendung von Filterfunktionen gegeben (siehe 6.2). Unverzichtbar ist jedoch eine Sprache zum Zugriff auf die Datenbank, um ihre Inhalte dem Benutzer zur Verfügung zu stellen oder neue Daten in die Datenbank einzuführen. Die grundlegenden Zugriffsmöglichkeiten auf eine NDB werden durch die Zugriffsfunktionen find zum Finden der Stelle, an der die gesuchten Daten in der NDB liegen, KAPITEL 4. DATENBANKEN 36 get zum Auslesen der Daten in der NDB, obtain zum Finden der Stelle, an der die gesuchten Daten in der NDB liegen, und dem nachfolgenden Auslesen der Daten10 , store zum Speichern der Daten in der NDB, erase zum Löschen von Daten in der NDB, modify zum Ändern von Daten in der NDB, connect und zum Herstellen bzw. disconnect zum Lösen der Verbindungen zwischen den Verbunden einer NDB realisiert. 4.5 Weitere grundlegende Begriffe zu Datenbanken 4.5.1 Transaktionen Eines der Grundkonzepte in bezug auf die Integrität der Daten in einer Datenbank, ist das Konzept der atomaren Transaktion. Darunter versteht man eine Arbeitseinheit der Datenbank, die entweder in ihrer Ganzheit erfolgreich oder in ihrer Ganzheit erfolglos durchgeführt wird11 . Der Begriff der Transaktion ist wichtig, um zum einen die Integrität der Daten zu wahren, um die Konsistenz der Daten und ihrer Beziehungen untereinander sicherzustellen, und um einen kontrollierten Ablauf bei der Bearbeitung der Daten durch mehrere Benutzer quasi-gleichzeitig zu ermöglichen. Die Transaktion entspricht also dem kritischen Abschnitt bei der Datenverarbeitung in Datenbanken und stellt ebenfalls die kleinste Zeitscheibe für miteinander konkurrierende Benutzer dar (Serialisierungsaspekt). Transaktionen unterscheidet man in solche, die den Zustand der Datenbank ändern, z.B. durch Modifizieren eines Datums, und solche, die den Zustand der Datenbank nicht ändern, z.B. durch reine Lesezugriffe. Im folgenden sollen nur zustandsändernde Transaktionen betrachtet werden. 10 [8], S. 804 führt diese Operation zusätzlich zu den bei [11], S. 307 beschriebenen an. Diese Operation wird hier deswegen erwähnt, weil es die in der LDB gewählte, kombinierte Variante ist. 11 “A transaction is an atomic unit of work that is either completet in entirety or not done at all.”,[11], S. 541 KAPITEL 4. DATENBANKEN 37 Wenn man annimmt, eine Datenbank befindet sich zu einem bestimmten Zeitpunkt in einem bestimmten Zustand, dann befindet sich die Datenbank nach der erfolgreichen Durchführung einer Transaktion in einem anderen Zustand. Der Ausgangsund der Endzustand sind stabile, gültige Zustände der Datenbank. Anders ist der Fall dagegen gelagert, wenn die Transaktion erfolglos ist. Dann befindet sich die Datenbank nach dem (erfolglosen) Beenden der Transaktion idealerweise in demselben Zustand wie zuvor. 4.5.2 Verwaltung mehrerer Benutzer durch Sperrungen Mit den Transaktionen wurden die kleinsten Ablaufseinheiten beim Zugriff von Benutzern auf die Daten in einer Datenbank vorgestellt. Sie sind eine der Voraussetzungen dafür, daß mehrere Benutzer quasi-gleichzeitig mit den Daten einer Datenbank arbeiten können, ohne sich in destruktiver Weise gegenseitig zu beeinflussen. Die Vermeidung dieser Beeinflussung findet auf einer aktuellen und einer strukturellen Ebene statt. Die strukturellen Voraussetzungen werden durch das DBMS geschaffen. Es sorgt z.B. dafür, daß die Aufträge der Benutzer in der Reihenfolge abgearbeitet werden, in der ihre Anfragen beim DBMS eingegangen sind. Weiterhin trägt es Sorge, daß immer jeweils nur eine Anfrage zu einem bestimmten Zeitpunkt im Sinne einer Transaktion, d.h. in Ganzheit und ununterbrechbar abgearbeitet wird. Als letztes kann ein DBMS Mechanismen zur Verfügung stellen, die es einem Benutzer ermöglichen, den Zugriff anderer Benutzer auf bestimmte Daten temporär auszuschließen. Ein solcher Mechanismus wird in Form eines Sperrmechanismus (engl. locking mechanism) eingerichtet. Das DBMS kann Sperrungen auf verschiedene Größeneinheiten ermöglichen: Sperren der gesamten Datenbank, wenn z.B. der Datenbankinhalt restrukturiert werden soll. Sperren bestimmter Datentypen, die nur gelesen werden dürfen Sperren einzelner Datensätze. Im weiteren soll das Sperren einzelner Datensätze (engl. record locking) näher betrachtet werden, da die ersten beiden Fälle entweder selten Anwendung finden oder KAPITEL 4. DATENBANKEN 38 nur durch Benutzer mit hohem Rechtestatus ausgeführt werden dürfen (z.B. durch die Datenbankadministratoren). Die Sperrung eines Datensatzes ist dann sinnvoll, wenn ein Datenbankbenutzer einen existierenden Datensatz modifizieren möchte. Üblicherweise würde er dazu über das DBMS den Datensatz auslesen, ihn modifizieren und dann dem DBMS den Auftrag geben, den ursprünglichen Datensatz in der Datenbank durch den modifizierten zu ersetzen. Das Problematische an diesem Vorgang liegt darin, daß der Vorgang des externen Modifizierens beim Benutzer eine gewisse Zeit in Anspruch nimmt. In dieser (vielleicht sehr kurzen) Zeitspanne könnte ein anderer Datenbankbenutzer denselben Datensatz modifizieren wollen, und, wenn er schneller als der erste Benutzer ist, dies auch tun. Seine Änderungen würden dann vom ersten Benutzer überschrieben werden. Der erste Benutzer muß also die Möglichkeit haben, den gewünschten Datensatz temporär vor den Zugriffen anderer Benutzer zu schützen, um ihn ohne Beeinträchtigung durch andere Benutzer der Datenbank bearbeiten zu können. Zum Sperren eines Datensatzes testet das DBMS, ob der Datensatz schon von einem anderen Benutzer gesperrt wurde. Danach sperrt es den Datensatz für den Benutzer und läßt ihn den Datensatz erneut auslesen. Der Benutzer hat dann den aktuellen, für ihn gesperrten Datensatz zur Verfügung. Dies muß in einer atomaren Operation erfolgen, damit kein anderer Benutzer in der Zwischenzeit den Datensatz für sich sperrt, und somit oben erwähnte Probleme auftreten können. Hierbei handelt es sich um grundlegende Probleme von Strategien zum gegenseitigen Ausschluß. Nach Modifikation des Datensatzes und dem Aktualisieren der Datenbank kann der Datensatz wieder für andere Benutzer freigegeben werden. Je nachdem, ob während der Sperrung andere Benutzer den betreffenden Datensatz auslesen können (natürlich immer mit dem Hinweis darauf, daß der Datensatz potentiell ungültig ist) oder ob die Sperrung auch eine Lesesperrung beinhaltet, spricht man von einer teilweisen (engl. shared lock) oder totalen (engl. exclusive lock) Sperrung. Im allgemeinen werden Sperrungen und ihre Verwaltung eigenen Modulen innerhalb des DBMS übertragen. Diese Module werden vor und während der Transaktionen zur Feststellung und Erzeugung der verschiedenen Sperrungen benutzt. Kapitel 5 Datenbankkonzepte in der Lexikondatenbank 5.1 Die Lexikondatenbank als Netzwerkdatenbank Wie werden nun die oben erklärten Konzepte in der LDB umgesetzt? Da die LDB dem Netzwerkdatenbank-Modell folgt, ist zuerst das Aussehen der Verbunde bzw. der Mengen zu beschreiben. 5.1.1 Verbunde Die LDB verwendet mehrere Verbund-Typen. Diese sind im einzelnen der Grundform-Verbund (vgl. Abbildung 4.1), der Allomorph-Verbund (vgl. Abbildung 4.2), der Paradigmen-Verbund und der Kommentar-Verbund. Diese brauchen hier nicht im einzelnen erläutert werden, da sie sich direkt aus den Grundeinheiten und deren Attributen in der ER-Darstellung 3.2 ableiten lassen. Die Verbund-Typen werden innerhalb der LDB entweder als “TransportContainer” realisiert, die nur während einer Transaktion gültige Daten enthalten, z.B. in Form von C-structs, oder in den Datensätzen als lineare Puffer, die zur Speicherung aus den Transport-Containern gepackt werden und zur Ausgabe wieder in die entsprechende Darstellung umgewandelt werden.1 1 vgl. zu den Filterfunktionen vgl. Abschnitt 6.2 39 KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 40 5.1.2 Mengen Mit der Darstellung der Mengen, also der Beziehungen zwischen den Verbunden, tritt eine besondere Eigenschaft der LDB zu Tage. In der LDB sind diese Beziehungen durch die Programmstruktur festgelegt. Sie sind also “hard-wired”. Dies steht offensichtlich im Widerspruch mit der Philosophie der Datenunabhängigkeit, die besagt, daß das Datenbankschema unabhängig von der Implementierung der Datenbank geändert werden kann. Allerdings ist der Einwand nicht von der Hand zu weisen, daß das Datenbankschema der LDB nur mit viel Aufwand geändert werden kann. Diese Vorgehensweise ist durch eine sehr wichtige Eigenart der Daten begründet, die mit der LDB zu verwalten sind. Nicht alle Daten, die in der LDB gespeichert werden sollen, werden von außen an die LDB übergeben, wie dies sonst bei Datenbanken der Fall ist. Der LDB werden nur Grundform- und Kommentareinträge übergeben. Vielmehr wird ein großer Teil der Daten, nämlich der durch linguistische Verfahren bearbeitete, erst während der Arbeit der LDB an einem Lexikoneintrag erzeugt2 . Man kann also davon sprechen, daß es in der LDB statische und dynamische Typen von Verbunden gibt. Die Grundform- und Kommentareinträge sind statisch, die Allomorph- und Paradigmeneinträge dynamisch. Wenn man den oben erklärten Begriff der Transaktion auf den Einfügevorgang in der LDB anwendet, kann man die Daten, die während einer Transaktion in der LDB erzeugt werden, so betrachten, als wenn sie der LDB schon bei der Übergabe des Grundformeintrags ebenso mitübergeben worden wären. Nach einer erfolgreichen Transaktion, z.B. Einfügen eines Eintrags in das Grundformlexikon, ist immer garantiert, daß auch alle zugehörigen Allomorphe generiert wurden, und die Verbindungen zwischen den Daten richtig aufgebaut wurden. Im anderen Fall wird der Eintrag zurückgewiesen und der Benutzer über den aufgetretenen Fehler benachrichtigt. Die LDB erfährt durch jede (schreibende) Transaktion eine Zustandsänderung. Alle Vorgänge, also auch die Allomorphgenerierung, sind in dieser einen Zustandsänderung beinhaltet. Neben diesen Überlegungen ist zu berücksichtigen, welche Vorteile es mit sich bringt, daß die Allomorphgenerierung aus dem Aufgabenfeld des Benutzers in das der LDB übergeht: 2 Daß und warum diese Erzeugung faktisch dann doch nicht in der LDB selbst stattfindet, wird im Kapitel über die Filterfunktionen ab Seite 63 näher erläutert. Dennoch ist die LDB die Initiatorin dieser Generierungsvorgänge. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 41 Dem Benutzer wird das Wissen um die einzelnen Schritte während der Generierungsvorgänge abgenommen. Fehlerquellen werden durch die Automatisierung des Vorgangs reduziert. Der Umfang der zur LDB zu übertragenden Daten ist erheblich geringer. Dies belastet das Netzwerk, über das die Daten übertragen werden, weniger. Einige Vorgänge, z.B. das Erzeugen eines automatischen Kommentars, liegen außerhalb der Beeinflussungsmöglichkeiten eines Lexikonbearbeiters und müssen deshalb in der LDB stattfinden3 . 5.1.3 Operationen und Zugriffsfunktionen Alle im Abschnitt 4.4.6 beschriebenen Zugriffsfunktionen sind für die LDB implementiert, wenn auch die Funktionalität zum Teil geringfügig von der allgemein beschriebenen abweicht. Zentral ist in einer NDB die Funktion find, die die Stelle in der NDB sucht, an der eine andere Operation, z.B. get oder modify stattfinden soll. find setzt nach erfolgreichem Auffinden dieser Position in der NDB die Navigationsindikatoren auf die entsprechenden Werte, so daß die nachfolgende Operation keine Suchzugriffe mehr benötigt. Im Gegensatz dazu steht die LDB, in der find zwar in jeder Zugriffsfunktion (z.B. getDbEntryForKey) durchgeführt wird, aber nicht als von außen zugänglicher Funktionsaufruf existiert. Dies ist sinnvoll, weil so z.B. die Funktion get, die intern getDbEntryForKey aufruft, ihren geforderten Charakter als atomare Zugriffsfunktion behält. Ebenso ist in der LDB die Funktionalität der Funktionen connect und disconnect implizit dadurch gegeben, daß das Einfügen eines Eintrags und das Herstellen der Verbindungen als atomarer Zugriff behandelt werden. So garantiert die LDB dem Benutzer, daß immer nur Einträge in die LDB aufgenommen werden, zu denen alle Allomorphe generiert werden konnten, und deren Paradigma auf diese Weise konsistent gehalten wird. Um die oben eingeführten Begriffe der Aufewahrungsoptionen und der Einfügeoptionen im Kontext der LDB anzuwenden, läßt sich sagen, daß in der LDB als Optionen die Zustände “automatisches Einfügen” und “feste Verbindungen” fest 3 Unter bestimmten Umständen ist die Einflußnahme des Lexikonbearbeiters aus Gründen der Dokumentation von Lexikonänderungen auch nicht erwünscht oder möglich. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 42 über den Quelltext eingestellt sind. Hinsichtlich der Konsistenz der Daten in der LDB sind keine anderen Vorgaben sinnvoll. 5.2 Funktionale Gliederung der Lexikondatenbank Abbildung 5.1 zeigt schematisch die funktionale Grobgliederung der LDB. Server Teildatenbank- Verwaltung Anfragen Remote Antworten Procedure Calls Befehlsverteiler Lexikon- Datenbank- Verwaltung Benutzer- Verwaltung Abbildung 5.1: Teilbereiche der LDB Wie man sehen kann, sind die vier funktionalen Teilbereiche der LDB: die Verwaltung der LDB und ihrer Ressourcen die Verwaltung der Teildatenbanken und ihrer Funktionen. die Benutzerverwaltung, die neue Benutzer in eine Benutzerliste aufnimmt (logging) und die Zugriffsrechte der angemeldeten Benutzer überwacht. der Server-Teil, in dem eingehende Anfragen übernommen, ausgewertet und den Einzelkomponenten der LDB zur Weiterverarbeitung übergeben werden. Nach der Verarbeitung der Daten gibt der Server-Teil (Siehe Abschnitt 7.1) den anfragenden Clients die Antwort auf die bearbeitete Anfrage. Bevor im Kapitel 6 auf die Implementation der LDB eingegangen wird, soll zuvor das Konzept der Teildatenbanken in der LDB erklärt werden. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 43 5.3 Das Konzept der Teildatenbanken Um die in Kapitel 3 gewonnenen Einsichten in die Art der Daten und ihre unterschiedlichen Formate umzusetzen, werden in der LDB für jeden Datentyp – im einzelnen sind das die Grundformeinträge, Allomorpheinträge, Paradigmeneinträge und Kommentareinträge – je eine, von den anderen Modulen getrennte Struktur zur Datenaufbewahrung und zum Zugriff auf die gespeicherten Daten eingesetzt. Diese Zugriffsstrukturen werden im weiteren Verlauf dieser Arbeit als Teildatenbanken bezeichnet, obwohl sie nur unzureichend die weiter oben beschriebenen Kriterien für Datenbanken erfüllen. Für die Wahl der Bezeichnung Teildatenbank ist vielmehr der Aspekt ausschlaggebend, daß alle Teildatenbanken zusammen die LDB ausmachen. Eine Teildatenbank ist ein nach außen hin abgeschlossenes Modul, das über einen Datenbank-Deskriptor verwaltet wird. Abbildung 5.2 zeigt im Überblick die wesentlichen Bestandteile der Teildatenbanken. Die Abbildung trennt die Komponenten der Teildatenbanken nach ihrer Lage im Vorder- bzw. Hintergrundspeicher. TeildatenbankDeskriptorBlock Index-Baum Cache Eingangs- / Ausgangs- Sperr- Filter- Funktionen Tabelle Schlüsselsatz-Tabelle (dynamischer Puffer) Index-Baum Datei Schlüsselsatz-Tabelle Datei Datensatz Datei im Vordergrundspeicher im Hintergrundspeicher Abbildung 5.2: Überblick über alle Bestandteile einer Teildatenbank und deren Lage im Speicher KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 44 Für den praktischen Umgang mit den Teildatenbanken wurden ihnen symbolische Namen gegeben. Nach den oben genannten Datentypen werden die im Quelltext module genannten Teildatenbanken mit den Kurznamen edit4 , allo, para und comm bezeichnet. Ein weiteres Modul mit dem Namen TCL ist nur logisch als Bezeichner vorhanden und dient lediglich dazu über den print-Befehl alle LDBFehlermeldungen für die Programmiersprache TCL in eine Datei auszugeben. Diese symbolischen Namen werden auch als Parameter für die Kommandos der in Abschnitt 8.2.2 vorgestellten Shell verwendet. Die Teildatenbanken besitzen alle grundsätzlichen Funktionalitäten, die ein Datenbankverwaltungssystem (DBMS) zur Manipulation von Datensätzen zur Verfügung stellen muß, Diese Funktionalitäten sind: das Einfügen von Datensätzen, das Löschen von Datensätzen, das Ändern von Datensätzen (u.U. als kombiniertes Löschen und Einfügen realisiert) das Suchen und Ausgeben von Datensätzen mit Hilfe des Suchschlüssels Desweiteren sind noch das Ausgeben (Exportieren) aller Datensätze (in eine Datei) das Einlesen (Importieren) von Datensätzen (aus einer Datei) zur Verarbeitung größerer Datenmengen zu erwähnen, die aber auch durch mehrmaliges Aufrufen der Funktionen Einfügen bzw. Löschen erfolgen können. Die letzeren laufen allerdings nicht auf der Ebene der Teildatenbanken, sondern auf der Ebene der LDB ab, die den Fortgang dieser Operationen kontrolliert. Die Teildatenbanken erhalten beim Aufruf ihrer Zugriffsfunktionen die Argumente in einem Aufrufverbund (dbDataRec) verpackt. Neben den Suchschlüsseln enthält dieser Aufrufverbund u.a. einen symbolischen Hinweis auf die globale Indextabelle der LDB. Die einzelnen Teildatenbanken setzen diesen symbolischen Verweis selbständig in die entsprechenden Indizies um. 4 Dieses Modul hieß ursprünglich base, angelehnt an den Namen der Grundformeinträge. Es ergaben sich aber Überschneidungen mit dem englischen Begriff für das Basis-Attribut, BASE, so daß der Name edit gewählt wurde. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 45 Um auf die Datensätze einer Teildatenbank zugreifen zu können, ist ein Suchschlüssel (eine Zeichenkette) erforderlich. Die nächsten beiden Abschnitte beschreiben die Anforderungen an einen Suchschlüssel und den in der LDB gewählten Ansatz zur Repräsentation der Suchschlüssel. 5.4 Anforderungen an den Suchschlüssel 5.4.1 Datenbanken mit festgelegter Maximallänge für Suchschlüssel Die besonderen Anforderungen an die Datenstrukturen und Verarbeitungsmechanismen in der LDB und ihre einzelnen Module ergeben sich aus dem Datenmaterial, d.h. dem Lexikon. Die meisten Datenbanken arbeiten mit Schlüsseln und Datensätzen fester Länge. Eine solche Verwendung ist angemessen, wenn z.B. Zahlen als Schlüssel verwendet werden, da diese immer eine Repräsentation mit fester Länge (z.B. der CDatentyp LONG) besitzen. Sie ist auch dann angemessen, wenn die maximale Schlüssellänge vor der Datenverarbeitung bekannt oder abschätzbar ist, wie z.B. bei Familiennamen im Falle einer Adreßdatenbank, und die Länge der meisten Einträge in Nähe der maximalen Schlüssellänge liegt. Hier spricht man von einem hohen Ausnutzungsgrad des Schlüssels. Nicht mehr angemessen ist dieses Vorgehen, wenn, wie im Falle des Lexikons einer natürlichen Sprache, die Schlüssel von beinahe beliebiger Länge sein können. Zudem gibt es in einem natursprachlichen Lexikon auf Morphembasis neben sehr langen Schlüsseln (z.B. im Deutschen gibt es sehr lange, aus semantischen Gründen nicht aufteilbare Komposita) auch sehr kurze Schlüssel (z.B. ein “e” für eine Flexionsendung). Die Länge der Schlüssel liegt hier in einem Bereich von einem Zeichen (bei e) bis zu dreißig oder mehr (z.B. 39 Zeichen beim bekannten Donaudampfschiffahrtsgesellschaftskapitän)5. Verwendet man für diese Wortform einen festen Schlüssel, so müßte er in diesem Fall mindestens 39 Zeichen lang sein. D.h. alle Schlüssel in dieser Datenbank müßten diese Länge haben. Man könnte noch 10 Zeichen als Reserve zugeben, damit eine neu auftauchende, vielleicht noch längere Wortform in die Datenbank aufgenom5 Es ist scheinbar unsinnig dieses Wort als solches ins Lexikon einzutragen, da es sehr wahrscheinlich von einem Morphologieprogramm als Kompositum analysiert werden könnte. Nichtsdestoweniger kann man sich vorstellen, daß dieses Wort als Paradebeispiel für die Wortkomposition im Deutschen aus pragmatischen Gründen als komplettes, zur komponierten Form homonymes Wort ins Lexikon eingetragen werden soll. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 46 men werden könnte. Jeder Schlüssel (auch das e) hätte dann diese feste Länge von ca. 50 Zeichen, womit beim Schlüssel für e 49 Zeichen ungenutzt bleiben würden. Beim derzeitigen Lexikon beträgt die durchschnittliche Oberflächenlänge bei den Grundformeinträgen 8 Zeichen, die maximale 29 Zeichen (beim Adjektiv gesellschaftswissenschaftlich). Für die folgende Größenabschätzung soll eine feste Schlüssellänge von 29 Zeichen angenommen werden. D.h. daß auf Reserven für eine möglicherweise längere Zeichenkette verzichtet wird. Bei einer Lexikongröße von ca. 21.500 Einträgen ergibt das einen durchschnittlichen Verlust von 21 Zeichen pro Eintrag, was insgesamt ca. 450.000 nicht genutzten Zeichen entspricht. Die Anzahl der genutzten Zeichen liegt bei ca. 185.000. Wenn man das Verhältnis zwischen genutzten Zeichen in den Schlüsselzeichenketten und den ungenutzten betrachtet, sind fast 2,5 mal mehr Zeichen ungenutzt als genutzt! Die Zahl von ca. 450 KByte erscheint angesichts zur Verfügung stehender großer Hintergrundspeichermedien (im GByte-Bereich) klein. Jedoch muß man sich vergegenwärtigen, daß die Zugriffsstrukturen zum größten Teil im Hauptspeicher liegen, um den Zugriff schnell zu gestalten. Rechnet man die ca. 21.500 Einträge auf zukünftige fünfzig- oder hunderttausend Einträge hoch, so werden aus den ca. 450.000 ungenutzten Zeichen schnell eine Million und mehr Zeichen. Es bietet sich aus diesen Gründen an, die Schlüssellänge dynamisch zu gestalten. Jeder Schlüssel bekommt gerade soviel Platz in der Zugriffsstruktur, wie er lang ist. Dasselbe gilt für die Länge der Datensätze, die ebenfalls sehr unterschiedlich sein kann. Statistische Informationen hierzu enthalten die Betrachtungen zur Datenkomprimierung (siehe dort). Datenbanken, deren Zugriffsstruktur auf festen Größen (feste Schlüssel- und Datensatzlänge) beruht, erlauben einen sehr schnellen Zugriff auf die Daten dadurch, daß sie jeden Datensatz über einen numerischen Index adressieren. Will man von Datensatz zu Datensatz springen, z.B. für die Suche, so wird dies über Hoch- bzw. Herunterzählen dieses Indexes erreicht. Das Einfügen von neuen Einträgen erfolgt auf sehr kompakte Art und Weise dadurch, daß ein nicht (mehr) belegter Datensatz gesucht wird, in den dann, exakt den zur Verfügung stehenden Platz füllend, der Datensatz kopiert wird. Da alle Datensätze die gleiche Länge haben, entfällt das Führen einer Fragmentliste, eines Speicherlochzählers o.ä. Wird ein Eintrag gelöscht, so wird er einfach als gelöscht markiert bzw. dereferenziert, so daß er nicht mehr durch einen Verweis zu erreichen ist, und steht fortan wieder für einen neuen Datensatz zur Verfügung. Wird in einer Datenbank mit festen Schlüssel- und Datensatzlängen dieselbe Anzahl Einträge gelöscht und dann wieder eingefügt, so vergrößert sich der Platzbedarf dieser KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 47 Datenbank nicht. Nicht so verhält es sich bei dem in dieser Arbeit verwendeten Konzept. 5.4.2 Elemente mit variabler Größe in den Teildatenbanken Durch die variable Länge der Schlüsselzeichenketten bzw. der Datensätze, wäre es notwendig, nach dem Löschen eines Datensatzes den freigewordenen Platz in der Datei zu notieren und ihn gegebenenfalls an einen neuen Datensatz zu vergeben, der kleiner ist oder exakt dieselbe Größe aufweist. Es kommen hierbei dieselben Strategien zur Anwendung wie sie auch Betriebssysteme zur Verwaltung des Vordergrundspeichers verwenden (First fit, best fit, ...). Dieser Aufwand wird vermieden, indem ein Fragmentieren der Datensatzdatei bewußt in Kauf genommen wird. Unter Fragmentierung ist zu verstehen, daß neue bzw. zu ersetzende Datensätze nur am Ende der Datei angehängt werden. Wird ein Datensatz gelöscht, erfolgt dies nicht durch Freigeben und Überschreiben des zugehörigen Bereichs in der Datei, sondern dadurch, daß sein Verweis im Indexbaum entfernt wird. Die Daten sind dadurch immer noch vorhanden, jedoch nicht mehr erreichbar. Daraus ergeben sich natürlich Konsequenzen für das Speicherplatzverhalten der Datensatzdatei. Werden häufig neue Datensätze hinzugefügt, wächst die Datensatzdatei mit der Zeit erheblich. Welches sind die Vorteile, die dieses Vorgehen bietet? Da die Datensätze, die gelöscht werden, als Datensatz nicht entfernt werden, kann man sie gewissermaßen als Backup Datensatz betrachten. Dies gilt auch für den Fall, daß unter dem gleichen Schlüssel ein neuer Datensatz eingefügt wird bzw. ein Datensatz durch Verändern ans Ende der Datei befördert wird. Dieses Backup läßt sich wiederherstellen und in die Datenbank reintegrieren. Desweiteren entfallen aufwendige Berechnungen, um den neuen Datensatz optimal einzufügen. Wie stark eine Datensatzdatei fragmentieren kann, zeigt beispielhaft Abbildung 5.3. Als Maßnahme gegen das Fragmentieren wurde eine Funktionalität zum Entfernen “toter” Datensätze implementiert, die eine fragmentierte Datenbank so in einen neuen Satz Dateien überträgt, daß die Lücken, die durch Löschen bzw. Verändern von Datensätzen entstanden sind, nicht mitkopiert werden. Die Backup-Einträge gelöschter oder wegbewegter Datensätze werden bei diesem Vorgang entfernt, so daß am Ende der Defragmentierung nur noch aktuell gültige Datensätze vorliegen. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 48 Datensatz-Datei Nicht referenzierte "Backup"-Datensätze Referenzierte, aktuelle Datensätze Abbildung 5.3: Datensatzdatei mit durch Fragmentierung entstandenen “Löchern” 5.5 Der Sperrmechanismus In der LDB ist für jede der Teildatenbanken ein unabhängiges, datensatzorientiertes Sperren möglich. Diese generelle Sperrmöglichkeit wurde jedoch auf ein Sperren der Grundformeinträge reduziert. Begründet ist dies darin, daß nur ein Schreiben der Grundform- und der Kommentareinträge möglich ist. Da in der LDB teilweises Sperren (engl. shared lock) eingesetzt wird, bei dem keine Schreibzugriffe anderer Benutzer auf gesperrte Datensätze mehr erfolgen dürfen, Lesen aber weiterhin erlaubt ist, bedeutet dies, daß ein Sperrmechanismus für die nicht beschreibbaren Teile der LDB (Allomorphlexikon und Paradigmentabelle) überflüssig ist. Für das Kommentarlexikon ist eine Schreibsperrung aus einem anderen Grund nicht erforderlich. Bei Kommentareinträgen wird durch das Beschreiben der bestehende Kommentareintrag erweitert, nicht aber überschrieben. Das Sperren eines Datensatzes wird über eine Sperrtabelle (engl. lock table) vorgenommen. Wie dies genau geschieht wird im Abschnitt 6.1.5 ausführlich erklärt. Die Sperrtabelle liegt im Vordergrundspeicher und muß beim Schließen der aktuell geöffneten Datenbank nicht gesichert werden, da es nicht sinnvoll ist, eine Sperrung über die aktuelle Sitzung eines Benutzers hinaus zu bewahren. Eine Sper- KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 49 rung unabhängig von den Datensätzen ist auch deswegen zweckmäßig, da nach einem möglichen, nicht regelgemäßen Server-Shutdown die Datensatzdatei nicht nach Sperrmarkierungen durchsucht werden muß. 5.6 Die Benutzerverwaltung Neben der Aufgabe, den Benutzern der Datenbank deren Daten auf vielfältige Weise zugänglich zu machen, steht im Hinblick auf die Betreuung und Verwaltung der Datenbankbenutzer die Sicherheit der Daten in der Datenbank im Vordergrund. Kein Benutzer soll unbefugt auf Daten zugreifen geschweige denn diese verändern dürfen. Genausowenig sollen sich die Benutzer gegenseitig beeinträchtigen können. Damit das DBMS zu jedem Zeitpunkt ausreichend Informationen über ihre Benutzer hat, müssen die Benutzer vom DBMS (oder einem Modul desselben) verwaltet werden. Die Verwaltung eines Benutzers beginnt damit, daß er sich beim DBMS anmeldet. Zu diesem Zeitpunkt werden die Zugangsrechte des Benutzers festgestellt. Dann kann der Benutzer die für ihn bestimmten Dienste des DBMS und der Datenbank in Anspruch nehmen. Wenn der Benutzer die Arbeit mit der Datenbank beenden will, muß er sich wieder beim DBMS abmelden. Ein weiteres Arbeiten mit der Datenbank ist erst wieder nach einer erneuten Anmeldung möglich. Um die verschiedenen Benutzer mit ihren unterschiedlichen Bedürfnissen und Zugangsrechten besser verwalten zu können, teilt man die Benutzer in Gruppen unterschiedlicher Priorität ein. Die Benutzer einer Datenbank lassen sich nach der Tragweite der für sie zugelassenen Operationen an und in der Datenbank in verschiedene Gruppen einteilen. Es bietet sich eine Einteilung in folgende drei Gruppen, eventuell mit Untergruppen, an. Die Gruppe der Datenbankverwalter besitzt die umfassendsten Möglichkeiten zur Manipulation der Datenbank und ihrer Daten. Daneben gibt es die Datenbankdesigner, die – erst einmal unabhängig von einer aktuell laufenden Datenbank oder einem bestimmten Datenbankverwaltungssystem – die Art der Daten und ihre Repräsentation festlegen. Als letztes ist die Gruppe der Endbenutzer zu nennen. Sie sind der eigentliche Adressat der Funktionalität der Datenbank. Sie können Daten in der laufenden Datenbank manipulieren oder abfragen, wiederum je nach den ihnen zugesprochenen Zugangsrechten. KAPITEL 5. DATENBANKKONZEPTE IN DER LEXIKONDATENBANK 50 Da in der LDB die logische Konzeptionsphase der Datentypen und ihrer Beziehungen mit der Implementierung der physikalischen Ebene zusammenfällt, ist in der LDB die Gruppe der Datenbankdesigner nicht vorgesehen. Ein Datenbankdesigner wäre im Falle der LDB auch gleichzeitig ihr Programmierer. Die innere Struktur der Lexikondaten wird im übrigen außerhalb der Datenbank durch die Grammatikund Lexikontheorie festgelegt. Lediglich die Beziehungen zwischen den Datentypen werden durch die Implementation der LDB festgelegt. Die Gruppe der Datenbankverwalter ist in der LDB vorhanden, um Tätigkeiten wie das Starten des Datenbankserverprogramms, das Öffnen einer Datenbank, das Defragmentieren oder das Schließen der Datenbank und das Beenden des Datenbankserverprogramms zu vollziehen. Die Benutzer dieser Gruppe sollen im folgenden mit Datenbank-Root-Benutzer, oder noch kürzer mit Root-Benutzer (engl. root users) bezeichnet werden. Diese Gruppe hat als einzige Zugriff auf alle implementierten externen Befehle der LDB. Die Gruppe der Benutzer wurde in der LDB aufgeteilt in privilegierte Benutzer (engl. privileged users), die Lexikoneinträge, nicht aber die LDB als ganzes beliebig manipulieren können, und normale Benutzer (engl. normal users), die auf die LDB nur lesend zugreifen können. Die Benutzergruppen werden über UNIX-Gruppenrechte gehandhabt. Dazu richtet der Systemadministrator des jeweiligen Rechnernetzes zwei Benutzergruppen ein. Auf diese Weise ist nicht nur die LDB durch das Überprüfen der Gruppenrechte geschützt, sondern auch die Benutzergruppen selbst durch die umfassenden Kontrollmöglichkeiten des UNIX-Betriebssystems. Damit die Definition, welche UNIX-Gruppenzugehörigkeit einen Root-Benutzer oder einen privilegierten Benutzer auszeichnet, nicht im Quelltext “hard-coded” ist, wird diese Definition in den jeweiligen Konfigurationsdateien zum einen des Datenbankserverprogramms und zum anderen der jeweiligen Datenbank festgelegt. Dazu sei auf Kapitel 8.1 verwiesen. Die Implementationsaspekte der Benutzerverwaltung, aber auch der anderen Konzepte werden im nächsten Kapitel aufgearbeitet. Kapitel 6 Die Implementation der Lexikondatenbank In den letzten Kapiteln wurde die Problematik der Gegenstände dieser Arbeit, die Beschaffenheit des Lexikons, die Zusammenhänge zwischen den linguistischen Komponenten Grundformlexikon und Allomorphlexikon, Datenbanken im allgemeinen und die Netzwerkdatenbanken im speziellen beschrieben. Weiterhin wurde gezeigt, wie die LDB von den vorgestellten Themenbereichen betroffen ist, und durch welche generellen Konzepte die Implementation der LDB die Problemstellung dieser Arbeit löst. In den Abschnitten dieses Kapitels werden die Implementationsphase der LDB und ihre Ergebnisse dargestellt. Nach einem Überblick über die Bestandteile der Teildatenbanken werden die dem Zugriff auf die Daten zugrundeliegenden Konzepte, Datenstrukturen und Funktionen vorgestellt. Im folgenden soll zuerst der Aufbau und die Funktionsweise der Teildatenbanken und danach ihre Zusammenschaltung zur LDB dargestellt werden. 6.1 Aufbau der verwendeten Teildatenbanken Aus der folgenden Darstellung (Abbildung 6.1) gehen die Komponenten der in dieser Arbeit implementierten Teildatenbanken hervor. Die Abbildung zeigt eine ursprünglich von Gerald Schüller implementierte Komponente, die Ausgangspunkt der Implementierung der LDB wurde. 51 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK Index-Baum 52 Schlüsseldatei Index-Seite Verweis Schlüsselzeichenkette Datensatz-Datei Verweis Datensatz Abbildung 6.1: Zugrifsstruktur mit einfachen Schlüsselzeichenketten Man kann deutlich die Dreiteilung in den Indexbaum, die Schlüsseltabelle und die Datensatzdatei sehen. Diese Anordnung wurde jedoch den Anforderungen der Speicherung eines Lexikons nicht gerecht, so daß sie entsprechend den in Abschnitt 6.1.2 beschriebenen Verbesserungen modifiziert werden mußte. In den nächsten Abschnitten werden die Bestandteile der Teildatenbanken beschrieben. 6.1.1 Der Indexbaum Immer dann, wenn man in Datenbeständen suchen möchte, tritt die Notwendigkeit zu Tage, die passende Datenstruktur für den Zugriff auf die Daten zu finden. Für das Suchen in Datenbeständen verwendet man Indizes. Hier sind neben der Indizierung über Streutabellen (engl. hash tables) Suchbäume in unterschiedlichen Varianten im Gebrauch. Im Falle der implementierten Datenbank wird ein spezieller Suchbaum als Zugriffsstruktur gewählt, um die Datensätze über Schlüssel zu indizieren. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 6.1.1.1 B ESCHREIBUNG VON 53 B-B ÄUMEN Der eingesetzte Indexbaum ist seiner Struktur nach ein B-Baum1 . Der B-Baum ist ein ausgeglichener Vielweg-Suchbaum, der sich besonders für eine Anwendung auf große Datenmengen anbietet, die (zum Teil) auf Hintergrundspeichern liegen. Er wurde erstmalig von R. Bayer und E.M. McCreight 1970 beschrieben2 . Auf die Kriterien für die Ausgeglichenheit des Baums wird im Verlauf dieses Abschnitts noch eingegangen werden. Ein B-Baum enthält als Grundbestandteil sogenannte Seiten (engl. pages). Eine Seite kann zwischen n und 2n Elemente enthalten. n wird dabei die Ordnung des BBaums genannt, n ist innerhalb des B-Baums konstant. Jede Seite besitzt neben den Elementen einen Verweis auf eine “linke” Seite. Die Elemente enthalten jeweils einen Verweis auf einen Datensatz in der Datensatzdatei (engl. data pointer) und einen Verweis auf einen “rechten” Nachfolgerknoten. Es gibt eine ausgezeichnete Seite, die Wurzelseite, die nur ein Element enthalten darf. Eine typische B-BaumSeite zeigt Abbildung 6.2. Der Zeiger auf die “linke” Nachfolgerseite ist im großen Kasten ganz links zu sehen, die Verweise auf die “rechten” Nachfolgerseiten sind Bestandteil der jeweiligen Seitenelemente. Ordnung des B-Baums Element 0 Zeiger auf Nachfolgeseite Datensatzzeiger Element 1 Nachfolgeseite Datensatzzeiger Nachfolgeseite Element n - 1 Datensatzzeiger Nachfolgeseite Element 2n - 1 Datensatzzeiger Nachfolgeseite Datensatzzeiger Nachfolgeseite Datensatzzeiger Nachfolgeseite Seitengröße Abbildung 6.2: Eine Seite eines B-Baums Wirth beschreibt die wesentlichen Eigenschaften der B-Bäume folgendermaßen: 1. “Jede Seite enthält höchstens 2n Elemente (Schlüssel) 1 Die Abkürzung B-Baum ist u.U. irreführend und könnte zu Verwechslungen mit einem Binären Suchbaum führen. An dieser Stelle und auch in weiten Teilen der Literatur wird mit B-Baum der Bayer-Baum und seine Varianten bezeichnet. 2 R. Bayer, E.M. McCreight, Organization and Maintenance of Large Ordered Indexes, Acta Informatica, 1, No.1 (1972), S.173-89, zitiert nach [36], S.249 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 54 2. Jede Seite, ausser der Wurzelseite, enthält mindestens n Elemente. 3. Jede Seite ist entweder eine Blattseite, d.h. hat keine Nachfolger, oder sie hat m+1 Nachfolger, wenn m die Zahl ihrer Schlüssel ist. 4. Alle Blattseiten liegen auf der gleichen Stufe. ”3 Aho präzisiert die Beschreibung der Wurzelseite, indem er erklärt, daß die Wurzelseite entweder selbst schon ein Blatt sein kann oder mindestens zwei Nachfolgeseiten aufweist4 . Besonderes Kennzeichen des B-Baums ist die Eigenschaft, daß alle Pfade zu den Blättern die gleiche Länge (d.h. Seitenebenentiefe) haben und dadurch alle Blattseiten, d.h. die Seiten, die keine Nachfolgeseite haben, auf dieser untersten Ebene liegen. Dies ist eine Folge der Ausgeglichenheit des B-Baums. Auf diese Art und Weise ergibt sich ein Zugriff mit konstanter maximaler Pfadlänge auf die Einträge. Der Worst-Case-Zugriff ist von vornherein durch die Tiefe des Baums festgelegt. Je nachdem, wie die Größe der Seiten gewählt wird, bleibt die Tiefe des B-Baums gering. So erreicht ein B-Baum der Ordnung 50 (Seitengröße maximal 100 Elemente) bei ca. 100000 Einträgen nur eine Tiefe von 3-4 Ebenen. Abbildung 6.3 zeigt als Beispiel5 einen B-Baum der Ordnung 2. Hier sind die Schlüssel nicht wie im Fall der LDB Zeichenketten, sondern Zahlen. 25 2 5 7 8 10 20 13 14 15 18 22 24 26 27 28 30 40 32 35 38 41 42 45 Abbildung 6.3: Ein B-Baum der Ordnung 2 Ein B-Baum ist jedoch kein vollständig ausgeglichener Baum, da, wie Wirth schreibt, “Bei der Suche nach einem Kriterium für kontrolliertes Wachstum [...] das der vollständigen Ausgeglichenheit schnell ausscheiden [wird], da 3 [36], S. 249 [1], S. 369 5 Der dargestellte B-Baum ist inhaltlich übernommen aus [36], S. 250 4 vgl. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 55 es zuviel Verwaltungsaufwand benötigt. Die Regeln [Anm.: für die Wiederherstellung der Ausgeglichenheit] müssen sinnvollerweise etwas abgeschwächt werden.“6 Das Kriterium für vollständige Ausgeglichenheit ist die Pfadlänge zu den Blättern. In einem vollständig ausgeglichenen Baum sind alle Pfade gleich lang und die beiden Flügel des Baums gleich “schwer”. Dies hängt mit dem Füllungsgrad der Knoten (beim B-Baum der Seiten) zusammen, der also ein Aspekt der Ausgeglichenheit eines Baums ist. Der Vorteil eines ausgeglichenen Baums ist die hohe Geschwindigkeit beim Suchzugriff und die geringe Anzahl an Zugriffen auf die Seiten des Baums und damit auf die Datei im Hintergundspeicher, in der die unteren Ebenen des B-Baums liegen. Nachteil eines ausgeglichenen Baums sind komplexe Restrukturierungsoperationen im Baum nach Einfüge- und Löschoperationen, da nach einer solchen Operation unter Umständen der Baum neu ausbalanciert werden muß. Das Ausgleichen erfolgt rekursiv, d.h. wenn die Vorgängerseite geteilt werden muß, da sie “übervoll” ist, gibt sie ihre neuen Einträge an ihren Vorgänger weiter usw. Der umgekehrte Vorgang findet beim Löschen statt. Hier kann es vorkommen, daß eine Seite “untervoll” wird, so daß sie mit ihrer Nachbarseite, die ebenfalls untervoll ist zusammengefaßt werden kann. Bei diesem Implodieren geht dieser Vorgang rekursiv in den Vorgängerbaum, bis die Ausgeglichenheit des gesamten Baums wiederhergestellt ist. Nun könnte man meinen, daß die Neuordnung des Baums in zeitlicher Hinsicht wesentlich stärker zu Buche schlägt, als der Gewinn, den man durch den schnellen Zugriff erhält. Um das zu widerlegen, muß man betrachten, wie ein B-BaumZugriff aussieht, bei dem auch der Hintergrundspeicher betroffen ist. Üblicherweise liegen die meisten Seiten des B-Baums im Hintergrundspeicher, bis auf die Wurzelseite, die sinnvollerweise dauerhaft im Vordergrundspeicher liegt, da schließlich alle Zugriffe auf den Baum über sie gehen. Wird eine Seite aus dem Hintergrundspeicher als nächste zu verarbeitende benötigt, wird sie in einen Pufferbereich im Vordergrundspeicher geladen. Das Suchen innerhalb dieser Seite geht dann sehr schnell vonstatten. Wird die Seitengröße passend gewählt, so lassen sich innerhalb der Seite Elemente z.B. mit binärer Suche sehr schnell finden. Hinzu kommt, daß im Normalfall das Verhältnis zwischen Schreibzugriffen und lesenden Zugriffen in eine Datenbank sehr stark zugunsten der lesenden Zugriffe überwiegt, 6 [36], S. 249 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 56 die keine Ausgleichsoperationen erforderlich machen. In den Teildatenbanken der LDB haben die Seiten eine Größe von 100 Elementen. Die Anzahl der durchschnittlichen Seitenzugriffe nZugri f f e beim Suchen berechnet sich über die Formel nZugri f f e = logSeitengröße nSchlüssel (6.1) wobei nSchlüssel die Anzahl der im Baum gespeicherten Schlüssel ist. Sollen 100000 Schlüssel verwaltet werden, so ergibt sich ein Suchverhalten von im Mittel log100 100000 Seitenzugriffen. Das heißt, daß nach Zugriffen auf 2,5 (2 - 3) verschiedene Seiten des Baums ein Schlüssel gefunden (oder definitiv nicht gefunden) ist. Die im Hintergrundspeicher verbrachte Suchzeit ist somit sehr kurz. Das eigentliche Suchen erfolgt sowieso im Vordergrundspeicher. Bei der vorliegenden Implementierung wird zudem ein Cache-Speicher für häufig benutzte Speicherseiten verwendet, so daß sich immer ein für das Suchen relevanter großer Teil des Indexbaums im Vordergrundspeicher befindet. Dies ist vor allem dann günstig für das Laufzeitverhalten, wenn Ausgleichsvorgänge im Baum stattfinden. Dies bestätigt auch Knuth mit Bezug auf in der Praxis durchgeführte quantitative Messungen: “Some experiments by E. McCreight have shown that this idea [Anm.: das Caching] is quite successful. For example, he found that with 10 page-buffers and m = 121 [Anm.: m bezeichnet die Seitengröße], the process of inserting 100,000 keys in ascending order required only 22 actual read commands, and only 857 actual write commands; thus most of the activity took place in the internal memory. Furthermore the tree contained only 835 nodes, just one higher than the minimum possible value [...] 834; thus the storage utilization was nearly 100 percent.”7 Mit “actual reads” und “actual writes” sind hier Zugriffe auf den Hintergrundspeicher bezeichnet, im Gegensatz zu den restlichen, gepufferten Zugriffen, die im Vordergrundspeicher ablaufen. 7 [21], S. 479 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 6.1.1.2 D ER I NDEXBAUM UND DIE VARIABLE 57 S CHL ÜSSEL ÄNGE Die Schlüssel in der verwendeten Datenbank sind die Lemmata der Lexikoneinträge, also Zeichenketten. Das heißt gleichzeitig, daß die Länge der Schlüssel variabel ist8 . Im Gegensatz zu einer Datenbank mit fester Schlüssellänge, bei der die Schlüsselzeichenketten Teil des Indexbaums sind, muß eine Zugriffstruktur mit variabler Schlüssellänge zumindest die variablen Teile auslagern, z.B. in eine Tabelle variabler Größe, die die Schlüsselzeichenketten aufnimmt. Die variablen Teile des Indexbaums müssen deswegen von den konstanten getrennt werden, da andernfalls ein effizienter Umgang mit den Seiten des Indexbaums während des Einlagerns bzw. Auslagerns aus dem Cache nicht mehr gewährleistet ist, da diese unterschliedlich groß werden könnten. Statt “blind” einen Seitenblock fester Größe aus dem Hintergrundspeicher zu lesen, müßte jeweils zuvor die Größe der Speicherseite berechnet bzw. ermittelt werden. Ebenfalls würde sich das Auffinden der Seite im Hintergrundspeicher schwieriger gestalten, da die Dateiadresse nicht mehr über einen Index zu berechnen wäre. Bedingt durch die variable Seitengröße wären auch die Dimensionen des Seitencaches schwer zu bestimmen, da nicht mehr von einer maximalen Seitengröße ausgegangen werden kann.. Werden die Schlüsselzeichenketten aus dem Indexbaum ausgegliedert, ergibt sich eine zusätzliche Ebene der Indirektion im Zugriff auf die Datensätze. Anstatt die notwendigen Schlüsselvergleiche im Indexbaum selbst durchzuführen, müssen die Schlüsselzeichenketten erst in der Schlüsseltabelle indiziert und dann verglichen werden. Da jedoch im vorliegenden Fall auch die Schlüsseltabelle im Hauptspeicher liegt, hat diese Indirektion wenig Einfluß auf das Laufzeitverhalten. Der Indexbaum enthält anstelle der Schlüsselzeichenkette selbst Informationen über die Schlüssellänge und einen Verweis auf dessen Position in der Schlüsseltabelle. Zudem enthält er auch noch Verweise auf die einzelnen Datensätze und ihre Länge. Der Rest des Indexbaums, die Index-Seiten und ihre Verweise, kann weiterhin, wie bei einer Datenbank mit fester Schlüssellänge, wie ein Vektor über Indizes zu adressiert werden. [11] bezeichnen einen solchen indirekten Index als Mehrebenenindex (“multilevelindexing”)9 . Die in der LDB verwendete Methode weicht jedoch von der bei [11] ab. Dort wird der Mehrebenenindex verwendet, um schon bei Zugriffen in der ersten Indexebene den Suchraum schneller einzuschränken. Diese Eigenschaft ist in der LDB zweitrangig. Vielmehr könnte man bei dem hier verwendeten Modell von einem zusammengesetzten Schlüssel sprechen, der lo8 Dies 9 vgl. wurde schon in Abschnitten 5.4.1 und 5.4.2 besprochen [11], S. 109ff KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 58 gisch gesehen aus Schlüsselzeichenkette und virtuellem Index (vgl. nächster Abschnitt) konkateniert wird. 6.1.2 Die Schlüsselsatztabelle Die Schlüsselsatztabelle war in der von G. Schüller übernommenen Zugriffstruktur eine Datei, in der alle Schlüsselzeichenketten (und nur diese) verwahrt wurden. Diese Struktur ist dann sinnvoll, wenn davon ausgegangen wird, daß für die Datensätze eindeutige Schlüssel verwendet werden. Wie in Kapitel 2.5 aber gezeigt wurde, müssen Schlüssel eines natursprachlichen Lexikons nicht immer eindeutig sein, d.h. es kann mehrere Datensätze mit dem gleichen Schlüssel geben. Hier ist das Problem zu lösen, mehrere Datensätze, die den gleichen Schlüssel besitzen, zu unterscheiden. Bevor man nun eine allgemeingültige Lösung für beliebig viele Unterschlüssel entwirft, sollte zuerst die quantitative Struktur der Lexikondaten betrachtet werden. Hier kann man sehen, daß selbst in größeren Lexika des Deutschen die Anzahl der Datensätze pro Schlüssel selten 5 überschreitet (gemessen an einem Lexikon für das Deutsche mit ca. 21.500 Einträgen; in den Grundformeinträgen ergeben sich maximal 4 Unterschlüssel, bei den Allomorphen maximal 5 Unterschlüssel pro Schlüssel). Diese Werte sind abhängig von der jeweiligen Sprache. Aus linguistischen Überlegungen heraus, wie komplex die Differenzierungsmöglichkeiten menschlicher Sprecher sind, wenn es um die Disambiguierung homonymer oder polysemer Wörter geht, kann man annehmen, daß sich die Grenzwerte wohl immer im Rahmen des angeführten Beispiels bewegen sollten. Diesem Umstand Rechnung tragend wurde in der vorliegenden Arbeit die Struktur gewählt, die Abbildung 6.4 zeigt: In der Schlüsseltabelle liegen nicht nur die Zeichenketten der Schlüssel, sondern auch die Verweise auf die zugehörigen Datensätze. Diese Verweise wurden aus dem Indexbaum entfernt und durch einen Verweis auf den Eintrag in der Schlüsseltabelle samt der Länge desselben ersetzt. Dadurch konnte der Indexbaum verkleinert werden. Ein Eintrag in der Schlüsseltabelle soll im folgenden als Schlüsselsatz bezeichnet werden. Mit Unterschlüsseln sind die verschiedenen Datensätze bezeichnet, die zu einem Schlüsselsatz gehören. Die einfachste Lösung scheint es zu sein, wenn man die verschiedenen Unterschlüssel durchnumeriert. Dies entspräche auch dem in Abschnitt 2.5 beschrie- KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK Index-Baum 59 Schlüssel-Datensatz-Datei Index-Seite Verweis Schlüssellänge Schlüsselstring Anzahl der Subindizes Subindizes Virt. Index 1 Verweis 1 Virt. Index 2 Verweis 2 Datensatz-Datei Verweise Datensatz Datensatz Abbildung 6.4: Zugriffsstruktur mit indirekter Indizierung der Datensätze benen Vorgehen in traditionellen Lexika. Wird ein Unterschlüssel hinzugefügt, bekommt er den nächsten nicht belegten Index (unter Umständen ein kleinerer als der derzeit größte) zugewiesen. Wird ein Unterschlüssel entfernt, so steht dessen Nummer wieder zur Verfügung. Außerdem läßt sich auf diese Weise beim Defragmentieren der Datenbank (vgl. Abschnitt 5.4.2) die Numerierung wieder fortlaufend herstellen. Gerechtfertigt ist ein solches Vorgehen dann, wenn die Zugriffstruktur vollkommen nach außen gekapselt ist und keine Verbindungen z.B. zu anderen Zugriffsstrukturen enthält. Da in der LDB jedoch die verschiedenen Teildatenbanken aufeinander verweisen, würden bald Inkonsistenzen in den Verweisen auftreten. Unter Berücksichtigung dieser Einschränkungen wurde deshalb ein “virtueller Index” eingeführt. Virtuell deswegen, weil er nicht die Position des Unterschlüssels in der Liste der Unterschlüssel darstellt, sondern vielmehr einen Namen, über den der zugehörige Unterschlüssel erreichbar ist. Zusammen mit der Schlüsselzeichenkette läßt sich so ein Datensatz eindeutig adressieren und finden. Zudem garantieren die virtuellen Indizes, daß durch die Abstraktion über die reale Position im Schlüsselsatz die Verbindungen zu den anderen Datenbanken aufrecht erhalten werden. Jeder Schlüsselsatz enthält neben der Schlüsselzeichenkette Informationen über die KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 60 Anzahl der zugeordneten Datensätze. Damit sind alle physikalisch vorhandenen Unterschlüssel gemeint, im Gegensatz zu den logischen, die nur tatsächlich über virtuelle Indizes erreichbare Datensätze bezeichnen. In Abbildung 6.5 soll das zum Aufbau der Schlüsselsätze Gesagte anhand eines Beispiels für einen fiktiven Schlüsselsatz zu den Datensätzen des Schlüssels klein dargestellt werden. 5 Anzahl virtueller Indizes: klein Schlüsselzeichenkette: Element ReferenzIndex 0 412 1 22 2 1350 3 711 4 3284 Virtueller Datensatz- DatensatzIndex: Adresse: Länge: BackupIndex BackupAdresse BackupLänge 0 0 0 290 340 320 1200 0 0 0 0 440 93 9 1211 350 NO_INDEX 0 0 12 1421 86 NO_INDEX 0 0 NO_INDEX 1 NO_INDEX NO_INDEX 3 Abbildung 6.5: Beispiel eines Schlüsselsatzes für den Schlüssel klein Durch Löschung dereferenzierte Datensätze und die ebenfalls nicht mehr beachteten zugehörigen virtuellen Indizes können zur Realisierung eines einfachen Backup-Mechanismus genutzt werden. Der aktuelle Wert des jeweiligen virtuellen Index wird auf einen Wert gesetzt, der “gelöscht” bedeutet. Der Wert des vorigen virtuellen Indexes, vor allem aber die Datensatzlänge und die Datensatzadresse werden im Schlüsselsatz aufgehoben, so daß über sie ein nur logisch gelöschter Datensatz “reaktiviert” werden kann. 6.1.3 Datensätze Die Datensätze stellen den unkompliziertesten Teil der Zugriffsstruktur dar. Alle Datensätze werden in einer Datei gespeichert. Ebenso wie die Schlüsseltabelle wird diese Datei im Verlauf der Zeit fragmentieren, da neue oder veränderte Einträge immer nur am Ende der Datei angefügt werden. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 6.1.3.1 S TRUKTUR DER 61 DATENS ÄTZE Die Zeichenketten der Datensätze sind nicht – wie in C üblich – Null-Byteterminiert. Dies hat seine Ursache darin, daß der Datensatz beliebige (Binär-) Zeichen enthalten kann. Deshalb ist das Zeichen mit dem Wert Null nicht geeignet, das Zeichenkettenende eindeutig zu markieren. Es wurde vielmehr der Weg beschritten, daß in der Schlüsseltabelle neben der Dateiadresse des Datensatzes auch dessen Länge vermerkt wird. Auf diese Weise wird immer nur die Anzahl von Zeichen aus den Datensätzen gelesen, die der jeweilige Datensatz einnimmt. Die interne Struktur eines Datensatzes ist für die Zugriffsstrukturen nicht wichtig, da der Datensatz als Folge von Zeichen behandelt wird. Im Abschnitt zu den Filterfunktionen wird ein Datensatz auch als linearer Puffer bezeichnet, da alle Zeichen unabhängig von ihrer für die jeweilige Teildatenbank typischen logischen Repräsentation in diesem Datensatzpuffer linear abgelegt werden. Die Funktionen der Teildatenbanken zum Lesen bzw. Schreiben eines Datensatzes, können nur ganze Datensätze manipulieren, nicht deren Inhalt. Diese Aufgabe obliegt den eigens dafür eingeführten Filterfunktionen. Im folgenden sollen die in Abbildung 5.2 gezeigten, aber bisher noch nicht erklärten Bestandteile der Teildatenbanken — nämlich der Datenbank-Deskriptor, die Sperrtabelle und die Filterfunktionen — erläutert werden. 6.1.4 Der Datenbank-Deskriptor Die einzelnen Zugriffsstrukturen benötigen für die Erfüllung ihrer jeweiligen Aufgaben Daten, die nur das jeweilige Modul betreffen. Solche Daten sind zum Beispiel der Dateiname der Teildatenbank, die einer Teildatenbank zugeordneten Dateizeiger (auf die Indexdatei, die Schlüsselsatz-Datei und die Datensatzdatei), die Lage der Indexbaum-Wurzelseite in der Indexdatei, die Anzahl der aktuellen Datensätze und die Anzahl der maximalen Unterschlüssel in den Schlüsselsätzen. Daneben müssen Angaben zum Seitencache des Indexbaums, der Sperrtabelle (s.u.) und der verwendeten Indextabelle verwaltet werden. Außerdem muß die jeweilige Teildatenbank festhalten, welche Filterfunktionen und Pipes ihr zugeordnet worden sind. Die eben beschriebenen Daten müssen zwar immer für jede Teildatenbank modulglobal verfügbar sein, nicht aber notwendigerweise für die gesamte LDB. Um diese logisch zusammengehörigen Daten einer Teildatenbank vor der LDB zu kapseln, aber andererseits von der LDB aus jederzeit referenzieren zu können, wur- KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 62 de ein Datenbank-Deskriptor eingeführt, der genau diese Aufgabe übernimmt. Für jede vorhandene Teildatenbank wird beim Öffnen derselben ein solcher Deskriptor angelegt und mit den entsprechenden Werten initialisiert. Auf diese Weise läßt sich jede Teildatenbank eindeutig über ihren Deskriptor identifizieren und von der LDB aus ansprechen. 6.1.5 Sperren von Datensätzen Um die verschiedenen Benutzer der LDB gegeneinander abzuschotten und gleichzeitige Schreibzugriffe auf denselben Lexikoneintrag zu verhindern, ist es notwendig, ein Sperrkonzept zu implementieren. Dieses Thema wurde schon allgemein im Abschnitt 4.5.2 erklärt und in Abschnitt 5.5 in bezug auf die LDB angerissen. An dieser Stelle soll der Aufbau der in der LDB verwendeten Sperrtabelle erläutert werden. In der Sperrtabelle werden Sperrzustände als zweiwertige Sperrungen (engl. binary locks) realisiert. Das heißt, daß jeder Eintrag in der Sperrtabelle durch das Eingetragensein die Sperrung des zugehörigen Datensatzes anzeigt. Wird die Sperrung aufgehoben, wird der entsprechende Eintrag aus der Sperrtabelle entfernt. Existiert für einen Datensatz kein Eintrag in der Sperrtabelle, ist er nicht gesperrt. Jeder Eintrag der Sperrtabelle besteht aus der Kennung des Benutzers, durch den der jeweilige Datensatz gesperrt wurde, der Schlüsselsatzadresse und dem virtuellen Index des Datensatzes. Eine Sperrung kann nur entweder durch den Benutzer, der die Sperrung vorgenommen hat, oder einen Datenbank-Root-Benutzer aufgehoben werden. Wenn man einen Datensatz sperren möchte, würde man offensichtlicherweise so verfahren, daß die Adresse des Datensatzes oder die Schlüsselzeichenkette in die Sperrtabelle eingetragen würden, anstelle der Schlüsselsatzadresse. Um die Datensatzadresse eintragen zu können, hätte beim Zugriff auf die Teildatenbank, bei dem die Schlüsselsatzadresse für den Suchvorgang ohnehin ermittelt werden muß, eine weitergehende Suche nach dem betreffenden virtuellen Index innerhalb des Schlüsseldatensatzes vorgenommen werden müssen. Dieser Vorgang wurde auf diese Weise eingespart. Das Eintragen der Schlüsselzeichenkette in die Sperrtabelle hätte bedeutet, daß die Sperrtabelle Elemente variabler Länge hätte enthalten müssen. Dies wird durch das Eintragen der Schlüsselsatzadresse, deren Platzbedarf konstant ist, vermieden. Das Programmodul db lock.c stellt mehrere Funktionen zum Umgang mit Sper- KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 63 rungen zur Verfügung. Kurz erwähnt werden sollen die Funktionen lockSet, mit der ein Datensatz gesperrt wird, unlockSet, mit der die Sperrung aufgehoben wird und checkLockSet, mit der der Sperrzustand für einen Datensatz überprüft werden kann. Wenn sich ein Benutzer von der LDB mit LOGOFF abmeldet bzw. wenn ein LDBRoot-Benutzer einen anderen Benutzer zwangsabmeldet, werden alle Sperrungen, die dieser Benutzer während seiner Arbeit mit der LDB vorgenommen hatte, freigegeben. 6.2 Das Konzept der Eingangs- und Ausgangsfilter Ein wichtiges Anliegen bei der Erstellung der LDB war die weitgehende Trennung der Funktionen, die die Lexikondaten verwalten, vom Format der jeweiligen Daten. Deshalb konnte bei den bisherigen Ausführungen zur LDB darauf verzichtet werden, das interne Format der Daten auf der Zeichenebene im einzelnen zu beschreiben. 6.2.1 Verwendete Datenformate Die LDB besteht aus vier Teildatenbanken, in denen die Daten jeweils unterschiedlich repräsentiert werden. Die unterschiedlichen Datenformate sollen hier aufgeführt und jeweils anhand eines Beispiels erläutert werden. Den Beispielen ist die Angabe des Suchschlüssels und des virtuellen Indexes vorangestellt. Der Grundformeintrag Die Grundlage der Arbeit am Lexikon ist der Grundformeintrag, der u.a. auch Klartexteintrag genannt wird. Das logische, vom linguistischen Verarbeitungsmechanismus abhängige MALAGA-Format wurde schon in Kapitel 2.3 vorgestellt. Aus technischer Sicht besteht der Grundformeintrag aus Textzeichen im ASCII-Format10 . Grundformeinträge enthalten keine Steuerzeichen (engl. non-printing characters, ASCII-0 bis ASCII-31) außer dem 10 Es handelt sich nicht nur um reine 7-Bit-ASCII-Zeichen. In MALAGA werden auch 8-BitZeichen, z.B. aus dem ISO-Zeichensatz Latin-1, verwendet, um Umlaute darzustellen. Eine speziell angepaßte MALAGA-Version kann sogar koreanische Zeichencodes verarbeiten. Da diese Zeichen sich jedoch mit einem Byte darstellen lassen, soll an dieser Stelle angenommen werden, daß sie wie ASCII-Zeichen behandelt werden können. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 64 Zeilenvorschub ASCII-10. Im Grundformeintrag eingebettet ist der Suchschlüssel für das Grundformlexikon. Dieser ist über ein ausgezeichnetes Attribut (z.B. im Falle des aktuellen Lexikons über LemOFl) zu erreichen. Ebenfalls aus dem Grundformeintrag wird das SF-Attribut extrahiert. [bank] 2 [LemOFl: WK: SB: SF: "bAnk", Substantiv, <Sg_0, Pl_e_n, F>, "bank2"]; Der Allomorpheintrag Der Allomorpheintrag liegt als binäre Zeichenfolge vor. Die einzelnen Zeichen sind entweder codierte Attribute oder deren Werte. Die Allomorpheinträge sind daher nicht direkt für menschliche Benutzer lesbar, sondern müssen zur Ausgabe für den Lexikonbearbeiter erst entsprechend aufbereitet werden. [bank] 2 [WK: Substantiv, T_OFl: "bank", SB: <Sg_0, nein, F>, Dim:nein] [bänk] 1 [WK: Substantiv, T_OFl: "bänk", SB: <nein, Pl_e_n, P>, Dim: ja] Der Paradigmeneintrag Im Paradigmeneintrag werden die Verweise zwischen Grundformeinträgen und Allomorpheinträgen abgelegt. Zu den Schlüsseln der jeweiligen Datensätze kommen deren virtuelle Indizes hinzu. Jeweils ein Grundformverweis und ein Allomorphverweis bilden ein Tupel (im Beispiel durch die äußeren eckigen Klammern dargestellt). Als weiteres sind in jedem Eintrag auch Verweise auf die noch nicht implementierte Stamm-Komponente11 einzutragen. Nicht vergessen werden darf, daß die Paradigmeneinträge einen zusätzlichen Verweis auf die Indextabelle enthalten können, wenn der betreffende Eintrag ein SF-Attribut aufweist. [bank] 2 [[bank 2] [bank 1]] [[bank 2] [bänk 1]] SF: [bank2] Der Kommentareintrag In den Kommentareinträgen müssen verschiedenste Daten gespeichert werden, um die im aktuellen ”Vorgang geänderten Daten zu dokumentieren: 11 Vgl. dazu Abschnitt 3.1 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 65 – die Art bzw. Bezeichnung des Vorgangs (Zeichenkette); – das Datum und die Uhrzeit des Vorgangs (Zahl); – die Daten des Benutzers, der den Vorgang veranlaßt hat. Dies sind im einzelnen seine UNIX-UserID und die Gruppen-ID (Zahlen); – der Rechner, von dem aus der Benutzer auf die Datenbank zugegriffen hat (Zeichenkette); – ein vom Benutzer hinzugefügter Kommentar (Zeichenkette). [bank] 2 ADD:maddin.db-adm@miranda:Sat Jul 15 20:26:26 1995;Test! Im Gegensatz zum Grundform- und dem Allomorpheintrag wird der Kommentareintrag bei Schreibzugriffen nicht vollständig ersetzt, sondern nur erweitert. Wenn mehr Kommentare als die maximal mögliche Anzahl vorhanden sind, wird bei erneutem Hinzufügen eines Kommentars der älteste (d.h. der am weitesten links stehende) entfernt und der neue eingetragen. Die Anzahl der zugelassenen Kommentare wird über die Konstante MAX COMMENTS im Quelltext festgelegt. 6.2.2 Die Filterfunktionen Innerhalb der LDB wäre es nur mit sehr großem Aufwand möglich, den in Abschnitt 6.2.1 beschriebenen, voneinander sehr verschiedenen Datenformaten gerecht zu werden. Deshalb wurde in der LDB ein Konzept eingesetzt, das diese Aufgabe modulabhängigen Filterfunktionen übergibt. Jeder Teildatenbank wird eine Eingabe- und eine Ausgabe-Filterfunktion zugeordnet. In dieser wird jeweils ein Lexikoneintrag aufbereitet. Soll der Eintrag in die LDB eingetragen werden, so wird er vom Eingabe-Format mit Hilfe der EingabeFilterfunktion ins jeweilige interne Format umgewandelt. Zur Ausgabe wird der interne Eintrag durch die Ausgabe-Filterfunktion geschickt und erst nach der entsprechenden Konvertierung ausgegeben. Für die LDB, die einer Teildatenbank einen Eintrag zur Ablage übergibt, ist der Zugriff der Teildatenbanken auf die Filterfunktionen vollkommen transparent, da erst die Teildatenbank die Filterfunktionen mit den übergebenen Daten aufruft. Abbildung 6.6 illustriert dies. Die gestrichelten Linien sollen die Trennung zwischen internem und externen Formaten markieren. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 66 Eingabedaten Eingabeformat Datenbank-Kern Eingangsfilter internes Format (internes Format) Ausgabefilter Ausgabeformat Ausgabedaten Abbildung 6.6: Datenbankmodule mit Eingabe- und Ausgabefilter Dieses Konzept hat mehrere Vorteile. Das Wissen um das Format der Einträge bleibt dem Zugriffsmechanismus vollkommen verborgen. Er übernimmt von der Filterfunktion einen Block Zeichen zusammen mit einer Angabe über dessen Länge. Dasselbe gilt für das Suchen von Einträgen. Gefundene Datensätze werden als Block an die Filterfunktion übergeben, die diese dann geeignet konvertiert. Zu keinem Zeitpunkt hat weder die LDB noch eine Teildatenbank Wissen über die interne Struktur eines Eintrags. Dadurch entfällt die Notwendigkeit einer Interpretation der Daten durch die Teildatenbank. Auf diese Weise ist es möglich, trotz der unterschiedlichen Anforderungen, die das Format der Daten an die Teildatenbanken stellt, immer die gleiche Zugriffskomponente zu verwenden. Diese Komponente kennt nur drei Formen von Daten: die Schlüsselzeichenkette, einen virtuellen Index und den Datensatz, der eine beliebige Folge von Zeichen einer bestimmten Länge ist. Kommentar- und Paradigmeneinträge enthalten Daten, die innerhalb der Datenbank erzeugt und gebraucht werden. Deswegen ist ihr Format sehr spezifisch für die LDB. Die Daten der Paradigmentabelle sind vom Benutzer nicht einsehbar, da es sich hierbei um die Darstellung der Verbindungen der einzelnen Teildatenbanken handelt. Die Kommentareinträge müssen erst von der Filterfunktion in lesbare Informationen umgewandelt werden, bevor sie zum Benutzer gelangen dürfen. Anders verhält es sich bei den Grundform- und den Allomorpheinträgen. Ihr Format wird nur durch die grammatische Theorie bzw. die Art der Datenbehandlung KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 67 im Schlüsselextraktor bzw. im Allomorphgenerator bestimmt. Ist es da nicht sinnvoll, die Schlüsselextraktion und die Allomorphgenerierung in die LDB zu integrieren? Wesentlicher Vorteil einer solchen monolithischen Lösung wären die “kurzen Wege” zwischen z.B. LDB und Allomorphgenerator. Jedoch müßte der Quelltext der LDB jedesmal geändert werden, wenn sich der Allomorphgenerator intern verändert.12 Dasselbe gilt auch für die Schlüsselextraktion. 6.2.3 Kommunikation mit LDB-externen Programmen In der LDB wurde ein anderer Weg beschritten. Unabhängig von der LDB existiert ein eigenständiges Programm, MALLEX, um Allomorphe zu generieren. Es ist Teil des Datenaufbereitungsprozesses von MALAGA. Wollte man dieses Programm von der LDB aus nutzen, müßte ein möglichst schneller Kommunikationsweg zwischen der LDB und MALLEX aufgebaut werden. Dieser Kommunikationsweg sollte zwar eine möglichst feste und verläßliche Verbindung darstellen, ohne jedoch MALLEX in die LDB zu integrieren. Dafür gibt es unter UNIX mehrere konzeptuell verschiedene Wege: Dateien: die Programme tauschen ihre Daten aus, indem sie ihre Eingabedaten aus einer Datei lesen, die das andere Programm beschrieben hatte, und ihre Ausgaben ebenfalls in eine Datei zum Gebrauch durch das andere Programm umleiten. Abgesehen vom Verwaltungsaufwand, der zum Mitteilen der Dateinamen und der Zusicherung der Benutzerrechte an der Datei nötig ist, ist auch das Problem der Synchronisierung der beiden Prozesse dadurch noch nicht gelöst. Gemeinsamer Hauptspeicher (shared memory): Diese Lösung ist sicher die schnellste. Jedoch setzt sie ein “intimes” Verhältnis der beiden Prozesse voraus, die wechselseitig in gemeinsame Speicherbereiche schreiben. Hier besteht ebenfalls das Synchronisierungsproblem. Signale und Nachrichten: Signale sollten nach [25] nur für das Anzeigen besonderer Systemzustände verwendet werden, während für ein Nachrichtensystem (engl. message passing) erst wieder ein Nachrichtenverteiler installiert werden müßte. 12 Zu Beginn des LDB-Projekts wurden Versuche unternommen, den Quelltext der LDB mit dem des Allomorphgenerators zu mischen. Dies scheiterte an sich überlappenden Bezeichnern, nicht übereinstimmenden Typdefinitionen, etc. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 68 Netzwerk-Kommunikation: Da die beteiligten Prozesse auf einem Rechner laufen sollen, ist diese Lösung nicht anwendbar. Pipes13 : Zwei Prozesse teilen sich die Standardausgabe- bzw. eingabe derart, daß die Ausgabe des einen die Eingabe des anderen Prozesses darstellt. Dies kann auch bidirektional geschehen, wenn die Ausgabe des zweiten Prozesses auf die Eingabe des ersten umgeleitet wird. 6.2.4 Pipes In der LDB fiel die Entscheidung aus mehreren Gründen zugunsten der Pipes aus. Pipes sind ein grundlegendes Konzept des Betriebssystems UNIX. Jedes UNIXSystem kennt Pipes14 . Die Beschickung einer Pipe mit Daten gestaltet sich denkbar einfach, weil man Ausgaben nur auf die Standardausgabe schreiben bzw. Eingaben von der Standardeingabe lesen muß. Dadurch, daß in einer Pipe Datenerzeuger und -verbraucher implizit aufeinander warten, entfällt die Notwendigkeit der Suche nach einer Lösung für das Problem der Prozeßsynchronisierung. Genauso irrelevant ist die Frage nach Zugriffsrechten der beteiligten Prozesse: Prozesse, die in einer Pipe laufen, werden von ihrem Elternprozeß mit dem Systemaufruf fork “geclont” und haben daher dieselben Rechte und Einschränkungen wie dieser. An dieser Stelle soll kurz beschrieben werden, wie unter UNIX eine Pipe geöffnet und der in der Pipe laufende Subprozeß gestartet wird, wie Daten über eine Pipe übertragen werden und wie die Anwendung von Pipes in der LDB vereinheitlicht wurde. Wie schon angedeutet, verwendet eine Pipe die Standard-Ein- und/oder Ausgabe des jeweiligen Prozesses. Außer bei Pipes mit Namen (engl. named pipes) müssen zwei Prozesse, die über eine Pipe Daten austauschen wollen, miteinander verwandt sein, und zwar in einer Eltern-Kind-Beziehung. Das Erzeugen eines neuen Kindprozesses geschieht mit Hilfe des UNIX-Systemaufrufs fork. Dabei werden neben anderen den Elternprozeß betreffenden Eigenschaften unter anderem auch die Standard-Ein- bzw. Ausgabe an den Kindprozeß weitervererbt. Es werden hier die Dateideskriptoren (engl. file handles) direkt weitergegeben. Zuerst ist der Kindprozeß eine exakte Kopie des Elternprozesses. Erst durch Ausführen des Systemauf13 In dieser Arbeit wird der englische Begriff Pipe verwendet, da auch in der Literatur keine deutsche Übersetzung zu finden ist. 14 “Tatsächlich kann kein Betriebssystem von sich behaupten, es sei UNIX, wenn diese Aufrufe [Anm.: pipe und dup] nicht wie gewohnt funktionieren.”([25], S. 193) KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 69 rufs exec15 ersetzt ein anderes Programm den Kindprozeß und übernimmt dessen Status als Kind des Elternprozesses. Normalerweise sind Pipes nur unidirektional. Das bedeutet, daß der Elternprozeß mit dem Kindprozeß über seine StandardAusgabe und dessen Standard-Eingabe verbunden ist. Bekommt ein solches Prozeßgespann Daten von außen, übernimmt sie der Elternprozeß an seiner StandardEingabe, verarbeitet die Daten, gibt sie über die Pipe an den Kindprozeß weiter. Dieser gibt die Daten nach der Verarbeitung über seine Standard-Ausgabe an die Außenwelt zurück. Dieser Vorgang kann nicht nur über eine, sondern auch mehrere solcher Stufen stattfinden. Eltern-Prozeß fd[0] = 2 fd[1] = 3 Kind-Prozeß fd[0] = 3 fd[1] = 5 Eingabedaten Ausgabedaten StandardEingabe StandardAusgabe StandardEingabe StandardAusgabe Abbildung 6.7: Anordnung der Prozesse in einer unidirektionalen Pipe 6.2.5 Pipes in der LDB Die Bedürfnisse der LDB liegen jedoch anders. In der LDB möchte man die Daten, die man dem Filterprogramm übergeben hat, möglichst auf demselben Weg wieder zurückbekommen. Die Lösung, sowohl Standard-Eingabe als auch Standard-Ausgabe beider Prozesse aufeinander umzulenken, indem die Dateideskriptoren übernommen werden, schließt sich aufgrund der Verklemmungsproblematik aus16 . Es bietet sich die Verwendung von bidirektionalen Pipes (im folgenden mit B-Pipes bezeichnet) an. BPipes sind nicht im eigentlichen Sinne bidirektional. Statt einer werden zwei Pipes aufgebaut, die gegenparallel verlaufen. Pipe 1 verbindet (wie üblich) die StandardAusgabe des Elternprozesses mit der Standard-Eingabe des Kindprozesses. Pipe 2 verbindet die Standard-Ausgabe des Kindprozesses mit der Standard-Eingabe des 15 Der Befehl exec existiert in mehreren Varianten, z.B. execlp, etc. Dies hängt mit den jeweils zu übergebenden Parametern u.ä. zusammen. Ausführlich erläutert wird dieser Systemaufruf in [33], S. 63ff, und [34], S. 207ff 16 vgl. hierzu die ausführliche Diskussion des Problems in [25], S.183ff. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 70 Elternprozesses. Die beiden jeweils nicht benötigten Standard-Ein- bzw. Ausgaben werden geschlossen. Hier ist zu beachten, daß bei einer bidirektionalen Pipe der Kindprozeß neue Dateideskriptoren aus denen des Elternprozesses mit Hilfe des Systemaufrufs dup dupliziert. Dies ist der wesentliche Unterschied zur unidirektionalen Pipe. Ersichtlich wird dies in Abbildung 6.8. LDB-Prozeß Filter-Prozeß fd[0] = 3 fd[1] = 4 fd[0] = 9 fd[1] = 10 StandardEingabe StandardAusgabe StandardEingabe StandardAusgabe Abbildung 6.8: Anordnung der Prozesse in einer bidirektionalen Pipe mit duplizierten Dateideskriptoren Dieses Konzept wurde nach Anpassungen in der LDB verwendet. Ein eigens bereitgestelltes Quelltext-Modul kümmert sich um das Öffnen der Pipe, das Lesen von bzw. das Schreiben auf die Pipe und das Schließen der Pipe. Die dabei erfolgenden Schritte wie Erzeugen des Kindprozesses als auch Duplizieren der Dateideskriptoren sind dadurch vollständig vor der LDB gekapselt. Diese verwendet einen Pipe-Deskriptor (Datentyp PIPE), der den jeweiligen Funktionen übergeben werden muß, ohne dessen Struktur kennen zu müssen. Durch Verwendung eines Pipe-Deskriptors ist die gleichzeitige Benutzung mehrerer B-Pipes möglich. Um einen reibungslosen Datenversand über die B-Pipe zu gewährleisten, wurde ein primitives Protokoll entwickelt. Bei diesem wird zu jedem Datum, das verschickt wird, zuerst eine Längenangabe des Datums in Bytes verschickt. Die Längenangabe selbst wird immer in einem Datum vom Typ LONG übergeben. So lesen die Pipe-Prozesse jeweils nur die verschickte Anzahl an Bytes, ohne sich in der Pipe “festzulesen”. Dies stellt auch eine primitive Überprüfung des Datenübertragungsvorgangs dar. Die Übertragung der Längenangabe ermöglicht es auch, Fehlernummern anstelle der Länge zu übermitteln. Hat die Längenangabe einen negativen Wert ungleich -1, folgt der dann als Fehlernummer zu interpretie- KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 71 renden Längenangabe eine Klartext-Fehlermeldung, und die Längenangabe ist die Länge der Fehlerzeichenkette mit negativem Vorzeichen. Durch das Konzept der Filterfunktionen ist die Möglichkeit gegeben, die Umwandlungsroutinen von den externen in die internen Datenformate gegen die LDB abzuschotten. 6.2.6 Schlüsselextraktion, Allomorphgenerierung und Allomorphdekodierung Die Einbindung der von einer linguistischen Theorie abhängigen Teile des Lexikonverarbeitungsprozesses ist ein Grundanliegen der LDB. Gleichzeitig soll aber eine möglichst klare Trennung der linguistischen Theorie von den Verarbeitungsstrukturen der LDB gewährleistet werden. Diese ist auch ganz im Sinne der Datenunabhängigkeit in Datenbanken. Im Lexikonverarbeitungsvorgang gibt es drei Stellen, an denen die linguistischen Aspekte des Lexikons in die Vorgänge der LDB eingreifen. Dies sind die Extraktion des Grundformschlüssels aus dem komplexen Grundformlexikoneintrag und das Generieren der Allomorphe zu einem Grundformeintrag. Daneben muß auch eine Funktion zur Wandlung der compilierten Allomorphe in ein lesbares Format vorhanden sein. Um in der LDB den Suchschlüssel zu einem Grundformlexikoneintrag zu finden, müßte er erst aus dem jeweiligen Eintrag extrahiert werden. Wie im Abschnitt 2.3 erklärt wird, greift man auf das Schlüsselattribut eines Lexikoneintrags mit speziellen Funktionen zu, die den Wert dieses Attributs, welches die gesuchte Schlüsselzeichenkette ist, an den Aufrufer der Funktion zurückliefert. Derselbe Vorgang sollte ablaufen, um das SF-Attribut aus dem Grundformeintrag zu extrahieren, wenn ein solches im Grundformeintrag durch den Benutzer angegeben wurde. Nützlich wäre es auch, wenn eine Funktion den Lexikoneintrag syntaktisch überprüfte, so daß dessen Wohlgeformtheit schon vor dem Eintragen in die Datenbank und der Allomorphgenerierung feststeht. Die Allomorphgenerierung ist ein Problem, das schon bei der Implementation MALAGAs gelöst wurde. Zur Beschreibung der Aufgaben des Allomorphgenerators sei auf [3] verwiesen. In der LDB ergibt sich eine weitere, mit linguistischen Mitteln zu lösende Problemstellung. Damit der Benutzer der LDB sich die generierten Allomorphe zu einem Grundformeintrag betrachten kann, müssen diese erst aus dem MALAGA- KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 72 lesbaren Binärcode in ein von Menschen lesbares Klartextformat gebracht werden. Da die Allomorphe nur eine andere Darstellungsform der Grundformeinträge sind, können sie durch MALAGA-Verbunde, die einem Grundformeintrag sehr ähnlich sind, dargestellt werden. Um diese eben aufgezählten Aufgaben umzusetzen, gibt es mehrere Möglichkeiten für die LDB: Einbinden der relevanten Funktionen aus dem MALAGA-Quelltext in den Quelltext der LDB Benutzung von Funktionen einer Bibliothek, die der MALAGAProgrammierer zur Verfügung stellt Benutzung schon vorhandener, getesteter, externer Programme, evtl. mit Modifikationen an denselben Die erste Möglichkeit scheidet, wie im Obigen schon beschrieben, aus programmiertechnischen Gründen aus. Die zweite Lösung ist interessant, wird doch der Code für die einzelnen Funktionalitäten gegenüber der LDB gekapselt. Dennoch müßte bei jeder Änderung an den entsprechenden MALAGA-Quelltexten die Bibliothek neu compiliert werden, und die LDB deshalb ebenfalls. Bei der Implementation der LDB wurde der dritte Weg begangen. 6.2.6.1 DAS P ROGRAMM MALFIL Mit der Implementierung MALAGAs wurden mehrere Programme erstellt, die die geforderten Funktionalitäten bereits enthalten. Diese Programme liegen als Dienstprogramme zur kommandozeilenorientierten Datenaufbereitung für MALAGA vor. Die Programmierschnittstellen zu diesen Programmen müssen so verändert werden, daß sie mit der LDB kommunizieren können. Einige Funktionalitäten liegen nur als interne Funktionen vor, so z.B. die lexikalisch-syntaktische Überprüfung eines Lexikoneintrags. Andere sind nur zur Verarbeitung von Daten in Dateien geeignet. Exemplarisch wird in Abbildung 6.9 das Programm MALLEX17 skizziert, in dem die meisten der benötigten Funktionalitäten schon implementiert sind. Aus der Anpassung dieser Dienstprogramme durch Björn Beutel und den 17 Die meisten zur MALAGA-Implementation gehörenden Programme haben das Präfix MAL-, dem ein Namensteil zur Charakterisierung der Programmtätigkeiten folgt. In diesem Fall bedeutet MALLEX “MALAGA-Programm zur Lexikonverarbeitung”. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 73 Datei-Behandlung Lexikalisch-syntaktische Überprüfung Allomorph-Generator Allomorph-Speicherung Abbildung 6.9: Funktionsgruppen in MALLEX Autor ging das Programm MALFIL18 hervor19 . MALFIL bietet der LDB folgende Funktionalitäten an: lexikalisch-syntaktische Überprüfung eines Grundformeintrags regelbasierte Extraktion des Suchschlüssels des Grundformeintrags regelbasierte Extraktion des SF-Attributs aus einem Grundformeintrag Generieren von Allomorphen zu einem Grundformeintrag Dekodieren eines im Binärformat vorliegenden Allomorpheintrags in eine von Menschen lesbare Form Durchführen der aufgezählten Vorgänge für einzelne Einträge als auch für Dateien mit mehreren Einträgen entsprechend dem gleichen Vorgehen in MALLEX Eingabe und Ausgabe der verarbeiteten Daten über eine bidirektionale Pipe Übermitteln von Fehlermeldungen an das aufrufende Programm 18 MALAGA Filterprogramm der Erstellung MALFILs wurde das Programm MALCOM zum Compilieren der Allomorphregeln so verändert, daß es auch die Schlüsselextraktionsregeln mit der Datei-Extension .fil lesen und verarbeiten kann. 19 Neben KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 74 Rücksetzen des Verarbeitungsmechanismus in einen sicheren Betriebszustand nach Auftreten eines Fehlers Diese Funktionsgruppen in MALFIL stellt Abbildung 6.10 schematisch dar. Im Datei-Behandlung Lexikalisch-syntaktische Überprüfung AllomorphGenerator Schlüsselextraktion AllomorphDekodierung Pipe-Behandlung, Befehlsverteilung Abbildung 6.10: Funktionsgruppen in MALFIL weiteren soll nicht auf spezielle Implementierungsaspekte von MALFIL eingegangen werden. Viele der Programmierungsaspekte in MALFIL laufen parallel zu denen in der LDB, z.B. die Programmierung der Pipe. Andere sind MALAGAspezifisch und fallen so aus dem Rahmen dieser Arbeit heraus. Voraussetzungen für den Betrieb MALFILs sind das Vorhandensein einer Segmentdatei mit der Dateiextension .seg, einer Filterregeldatei mit der Dateiextension .fil und einer Allomorphregeldatei mit .all als Dateiextension. Mit Hilfe des Programms MALSEG, das zur Implementation MALAGAs gehört, wird zuerst die Segmentedatei compiliert. Dann werden mit dem Programm MALCOM die Filterregeln und die Allomorphregeln compiliert. Erst wenn diese Vorgänge abgeschlossen sind, kann MALFIL gestartet werden. MALFIL meldet Fehler, wenn die Version des erzeugten Binärcodes nicht mit der Programmversion übereinstimmt, oder die Segmentedatei jünger als die Regeldateien ist. 6.2.6.2 B EISPIEL F ÜR DIE KOMMUNIKATION MALFIL S MIT DER LDB Möchte die LDB die Funktionalitäten MALFILS benutzen, startet die LDB mit Hilfe der bereits erwähnten Pipe-Befehle einen MALFIL-Prozeß in einer Pipe. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 75 Nach der internen Initialisierung MALFILs schickt dieses an die LDB ein Zeichen, das den Bereitschaftszustand MALFILs signalisiert. Die LDB und MALFIL halten sich beide an das oben erklärte Protokoll zur Datenübertragung. Wenn die LDB will, daß MALFIL aus einem Grundformeintrag den Schlüssel extrahiert, dann schickt sie über die Pipe dem MALFIL-Prozeß zuerst das Befehlswort für die Aktion Schlüssel extrahieren, “FILTER”. Danach folgt als nächstes entweder der Grundformeintrag oder der Name einer Datei, in der einer oder mehrere Grundformeinträge abgelegt sind. MALFIL prüft diesen Eintrag auf lexikalische und syntaktische Gesichtspunkte hin. Ist der Eintrag wohlgeformt, sucht MALFIL mit der Filterregel das Schlüsselattribut (z.B. LemOFl) und legt dieses in die Pipe. Danach legt MALFIL den überprüften (und dabei sortierten) Grundformeintrag in die Pipe. Dann wird, so vorhanden, das SF-Attribut gesucht und in die Pipe gelegt. Als letzte Aktion MALFILs schreibt der Prozeß eine EintragsendeMarkierung in die Pipe. Anhand dieser kann die LDB ersehen, daß sie nun keine Daten mehr von der Pipe lesen soll und kann, ohne erneut vorher MALFIL einen Auftrag erteilt zu haben. Sollen Einträge aus einer Datei verarbeitet werden, wird am Ende des gesamten Ablaufs eine Vorgangsende-Markierung (last allo) auf die Pipe gelegt. Derselbe Vorgang läuft analog für die Allomorphgenerierung ab, mit dem Unterschied, daß hierbei zuerst die Allomorphoberflächenzeichenkette, die compilierten Kategoriesegmente und die Basiszeichenkette in die Pipe geschrieben werden. Auch hier wird das letzte generierte Allomorph mit einer Eintragsende-Markierung versehen. Im folgenden wird die zur Zeit in der LDB verwendete Filterregel dargestellt. Sie folgt in ihrer Syntax den Allomorphregeln MALAGAs. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 76 initial-rules schlüssel-und-SF-extrahieren; allo-rule schlüssel-und-SF-extrahieren; start $Grundform; # vorsichtshalber das SEM-Feature auf einen leeren String setzen $SEMKEY := "\"\""; # existiert SF in $Grundform ? if SF in $Grundform then # ... dann extrahieren set $SEMKEY := $Grundform.SF; end; case # existiert AK in $Grundform ? of AK in $Grundform: # .. dann { und } aus der Oberfläche entfernen assert match $Grundform.LemOFl = $Of1:"[ˆ{]*" & "{" & $Of2:"[ˆ}]*" & "}" & $Of3:".*"; allo $Of1 & $Of2 & $Of3, cat $Grundform, base $SEMKEY; # oder haben wir ein K"urzenzeichen vorliegen? of match $Grundform.LemOFl = $OF1:".*" & "’" & $OF2:".*": # ... dann ’ aus der Oberfläche entfernen allo $OF1 & $OF2, cat $Grundform, base $SEMKEY; else # sonst normale Oberfläche nehmen allo $Grundform.LemOFl, cat $Grundform, base $SEMKEY; end; end; KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 77 6.3 Die Lexikondatenbank 6.3.1 Verwaltungsdatenstrukturen der Lexikondatenbank 6.3.1.1 D ER LDB-D ESKRIPTOR -B LOCK Analog zum Datenbank-Deskriptor20 der einzelnen Teildatenbanken gibt es auch für die LDB als Ganzes einen Deskriptor. Dieser LDB-Deskriptor beschreibt die gerade geöffnete Datenbank. Der LDB-Deskriptor wird im weiter unten erklärten Server-Verwaltungsverbund eingetragen, wenn eine Datenbank geöffnet ist. Andernfalls läuft nur das Serverprogramm und der Eintrag für den LDB-Deskriptor ist auf NULL-Zeigerwert gesetzt. Mit der Feststellung, daß der LDB-Deskriptor eine geöffnete Datenbank beschreibt, wird auch gleich deutlich, welche Informationen im LDB-DeskriptorBlock gespeichert werden: der Basisname der geöffneten Datenbank, z.B. /projects/ldb/data/lex der Name der Konfigurationsdatei der geöffneten Datenbank, z.B. /projects/ldb/.lexiconrc Verweise auf die Datenbank-Deskriptoren der Teildatenbanken der Modus, in dem die Datenbank geöffnet wurde (mögliche Werte sind “rw” und “r+” (engl. read-write) für Lesen und Schreiben, und “ro” (engl. readonly) für Nur-Lesen). ein Verweis auf die globale Indextabelle die Namen der Filterprogramme und ihre Aufrufoptionen, z.B. /projects/ldb/filter/malfil Die Werte für die einzelnen Felder des LDB-Deskriptors werden entweder vom Benutzer, der die Datenbank öffnet, eingegeben, z.B. der Modus, in dem die Datenbank geöffnet wird, oder aus der Konfigurationsdatei gewonnen. Diese wird in Abschnitt 8.1 noch eingehend besprochen. Der LDB-Deskriptor stellt den datenbezogenen Verwaltungsverbund dar, während der im Anschluß besprochene Server-Verwaltungsverbund Aspekte des ServerBetriebs abdeckt. 20 vgl. Abschnitt 6.1.4 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 6.3.1.2 78 D ER S ERVER -V ERWALTUNGSVERBUND Der Server-Verwaltungsverbund enthält einen LDB-Deskriptor-Block, einen Verweis auf die Benutzertabelle und den Namen eines Verzeichnisses, in das der LDB-Server seine Fehler- bzw. Betriebsmeldungen umleiten kann. Daneben wird hier vermerkt, ob der LDB-Server schon initialisiert wurde. Der ServerVerwaltungsverbund ist somit ein Container für wichtige, serverbezogene, global verfügbare Informationen. 6.3.2 Die Indextabelle In einer Netzwerkdatenbank können die Beziehungen zwischen den einzelnen Verbunden auf unterster, physikalischer Ebene verschieden dargestellt werden. Aufgrund des Konzepts der Datenunabhängigkeit ist die konkrete Darstellung der Beziehungen meist ein Aspekt, der die spezielle Implementation betrifft. In der LDB werden die Beziehungen zwischen den einzelnen Verbunden nicht auf der Basis von Dateiadressen o.ä., sondern durch symbolische Verweise aufrechterhalten. Zu jedem Eintrag einer Teildatenbank der LDB gibt es einen eindeutigen Suchschlüssel, der zweigeteilt ist in eine Schlüsselzeichenkette und einen virtuellen Index. Diese Struktur wird ausführlich in 6.1.2 erläutert. Hier soll ein kurz auf die Verteilung dieser Verweise in der LDB eingegangen werden. Der Suchschlüssel kann als symbolischer Verweis auf einen Eintrag in einer Teildatenbank angesehen werden. Bedingt dadurch, daß die zu jedem Grundformeintrag generierten Allomorphe oftmals die gleiche Oberflächenzeichenkette haben, die zudem auch mit der Basiszeichenkette übereinstimmen kann21 , kommt es sehr oft vor, daß die Schlüsselzeichenketten der verschiedenen Teildatenbanken übereinstimmen. Da die verschiedenen Datensätze zu einem Grundformeintrag immer in einer Transaktion in die verscheidenen Teildatenbanken eingetragen werden, stimmen häufig zudem auch die virtuellen Indizes der Einträge überein. Dies führt in solchen Fällen zu einer mehrfachen Redundanz, da diese Kombination aus Schlüsselzeichenkette und virtuellem Index für die Verweise der einzelnen Teildatenbanken untereinander benötigt wird. Die Verweise werden sowohl im Grundform-, im Allomorph- als auch im Paradigmeneintrag vermerkt. Hier liegt ein offensichtlicher Widerspruch 21 Wie in Abschnitt 3.1 dargelegt, wird die Basiszeichenkette in den meisten Fällen aus der Oberflächenzeichenkette abgeleitet. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 79 mit der eigentlichen Aufgabe einer Datenbank, der Redundanzvermeidung, vor. Um eine Abhilfe für dieses Problem zu schaffen, wird eine Indextabelle erstellt, in der für jeden Verweis ein Eintrag angelegt wird. Dabei spielt es keine Rolle, auf welche Teildatenbank damit verwiesen wird, da die Indextabelle außerhalb der einzelnen Teildatenbanken liegt und somit von diesen allen zu erreichen ist. Sind zwei Verweise identisch (d.h. sie stimmen in Schlüsselzeichenkette und virtuellem Index miteinander überein), erhalten sie denselben Eintrag in der Indextabelle. In den jeweiligen Komponenten (z.B. Grundformlexikon) wird daher der Verweis auf eine andere Komponente (z.B. Paradigmentabelle) nur noch in Form des Indexes dieses Eintrags in der Indextabelle vorgenommen. Diese Methode senkt den Redundanzgrad und verkleinert die Datensätze der einzelnen Komponenten. Mehr noch, da der Index der Indextabelle eine feste Größe hat, ist er viel leichter zu speichern als die in ihrer Länge variable Schlüsselzeichenkette mitsamt des virtuellen Indexes. Aus der Tatsache, daß die Indextabelle im Vordergrundspeicher liegt, ergeben sich erhebliche Geschwindigkeitsvorteile gegenüber einer Lösung, bei der die Verweise im Hintergrundspeicher aufbewahrt würden. 6.3.3 Das Aufbauen der Verbindungen zwischen den Teildatenbanken Im Kapitel 3.2 wurde erläutert, wie die Beziehungen zwischen den verschiedenen Lexikoneintragstypen (Grundform- und Allomorphlexikon) aussehen, und welche Probleme daraus entstehen können. Auf welche Weise die Beziehungen zwischen den Datengruppen aufgebaut werden, soll am Beispiel einer der zentralen Funktionen des LDB-Programms erläutert werden, der Funktion addEditEntry. Diese Funktion ist zusammen mit der Funktion replaceEditEntry die einzige Stelle in der LDB, an der die Verzeigerung der einzelnen Module vorgenommen wird. Beide Funktionen fügen einen neuen Grundformeintrag in die LDB ein. replaceEditEntry wird verwendet um einen bestehenden Eintrag zu modifizieren und löscht vor dem Einfügen des neuen Eintrags den alten. Nach dem Initialisieren des Puffers für die noch zu generierenden Allomorphe wird der neu einzutragende Lexikoneintrag an das externe Filterprogramm MALFIL geschickt. Dieses extrahiert den Suchschlüssel für den Eintrag, überprüft den Eintrag auf Wohlgeformtheit und extrahiert ebenfalls das SF-Attribut. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 80 Danach wird der Suchschlüssel normalisiert, d.h. in eine Zeichenkette in Kleinschreibung überführt. Dabei werden auch Umlaute und Sonderzeichen nach ISO Latin1 berücksichtigt. Im folgenden wird überprüft, ob es zu dem betrachteten Grundformeintrag in der LDB schon einen identischen Eintrag gibt. Wenn ja, dann ist das Eintragen unnötig und der Vorgang wird hier ohne Fehler abgebrochen, da ein nochmaliges Eintrag den inhaltlichen Zustand der LDB nicht ändern würde. In einer Schleife werden danach alle Allomorphe zu diesem Grundformeintrag generiert. Die generierten Allomorphe werden im oben erwähnten Puffer gesammelt. Bei der Allomorphgenerierung wird neben den Allomorphoberflächen und der Kategorie auch die Basis eines Grundformeintrags extrahiert. Da alle hier generierten Allomorphe aus einem Grundformeintrag abgeleitet werden, müssen alle Allomorphe dieselbe Basis haben. Die Basis wird ebenfalls zwischengespeichert. Erst wenn alle Allomorphe generiert sind, wird über die Basiszeichenkette der zu diesem Grundformeintrag gehörige Paradigmeneintrag ermittelt. Dabei wird ein u.U. im ersten Schritt extrahiertes SF-Attribut zur Disambiguierung gleicher Basiszeichenketten berücksichtigt. Existiert zu der entsprechenden Basis noch kein Paradigmeneintrag, so wird der nächste freie virtuelle Index im Eintrag der Paradigmentabelle ermittelt. Andernfalls wird der virtuelle Index des gefundenen Paradigmeneintrags verwendet. An dieser Stelle ist die Gültigkeit aller einzutragenden Daten festgestellt: der Grundformeintrag ist überprüft, alle Allomorphe ordnungsgemäß erzeugt, ein Paradigmeneintrag steht zur Verfügung. Es ist wichtig, daß der Paradigmeneintrag, wenn vielleicht auch nur als leerer Eintrag, schon zu diesem Zeitpunkt vorhanden ist, weil dadurch seine Schlüsselzeichenkette und sein virtueller Index verfügbar sind. Diese werden beim Eintragen der Daten in die einzelenen Module benötigt, um die Rückverweise in den Modulen auf die Paradigmentabelle einzurichten. Bis hierher wurden noch keine Daten in der LDB verändert. Das Einfügen der Daten wurde ans Ende der Funktion geschoben, so daß möglichst alle Daten zur Verfügung stehen, wenn ein Zustandsübergang der LDB stattfinden soll. Nun wird durch Einfügen des Grundformeintrags in das Grundform-Modul zu dessen Schlüssel ein virtueller Index ermittelt. Danach werden alle Allomorphe in das Allomorph-Modul eingefügt. Ergebnis jeder Einfügeoperation sind die Schlüsselzeichenkette und der virtuelle Index des eingefügten Datensatzes für dasjenige Modul. Für jeden Allomorpheintrag, der eingefügt wurde, wird im Paradigmeneintrag ein Allomorph-Grundform-Tupel eingetragen. Genau an dieser Stelle wird also die KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 81 Verzeigerung der einzelnen Module vollzogen. Nach Abschluß dieses Vorgangs wird der Paradigmeneintrag (zurück-)geschrieben. Damit ist das Eintragen eines kompletten Lexikoneintrags in die LDB beendet. Alle Verzeigerungen zwischen den verschiedenen Teildatanbanken sind hergestellt. 6.3.4 Die Benutzerverwaltung der Lexikondatenbank Wie schon in Abschnitt 5.6 beschrieben, erfolgt die Einstufung der Benutzer über deren Zugehörigkeit zu einer UNIX-Benutzergruppe. Die Festlegung der potentiellen Root-Benutzer muß schon beim Start des LDB-Serverprogramms erkannt werden. Schließlich ist das Starten des LDBServerprogramms ein Vorgang, zu dem nur wenige Benutzer die Berechtigung haben sollten. Deshalb wird die UNIX-Gruppe, die die Root-Benutzer stellt, schon beim Start des Servers – als eine von dessen ersten Aktivitäten – festgestellt. Ist der Benutzer, der versucht das Serverprogramm zu starten, durch seine Benutzergruppenzugehörigkeit nicht dazu berechtigt, bricht das Serverprogramm sofort ab. Intern verwaltet die LDB die Benutzer, die mit ihr arbeiten wollen, in einer Benutzertabelle. Dabei werden folgende Daten zu einem Benutzer in die Benutzertabelle eingetragen: die UNIX-User-ID des Benutzers die UNIX-Group-ID des Benutzers der Name des Rechners, von dem aus der Benutzer mit der LDB arbeitet die Prozeß-ID des Benutzerprozesses Über die User-ID und die Group-ID kann ein Benutzer innerhalb eines UNIXSystems (Cluster, Subdomäne) eindeutig identifiziert werden. Da beide Zahlen im LONG-Format vorliegen, sind sie dem Klartextnamen des Accounts bzw. der Gruppe vorzuziehen, da diese in ihrer Länge nicht konstant sein müssen. Außerdem ist diese Methode weniger speicherplatzintensiv. Der Name des Benutzerrechners wird durch einen UNIX-Betriebssytemaufruf aus den Daten ermittelt, die das RPC22 dem LDB-Serverprogramm zur Verfügung stellt. Er wird in der Benutzertabelle als Zeichenkette abgelegt. Die Prozeß-ID 22 vgl. Abschnitt 7.2.2 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 82 des Benutzerprozesses wurde deswegen in die Benutzertabelle aufgenommen, um den Benutzer nicht nur clusterweit, sondern auch dann eindeutig identifizieren zu können, wenn der Benutzer mehrere Zugangsprogramme zur LDB auf einem Rechner gleichzeitig betreibt. Schließlich könnte ein Benutzer in mehreren Instanzen des LDB-Zugangsprogramms mehrere Verbindungen mit unterschiedlichem Gruppenstatus zur LDB aufbauen. Die Aufnahme der Prozeß-ID in die Benutzertabelle ist auch durch die Benutzung des Programms ldbcall motiviert. Darauf wird bei der Vorstellung des Programms xLDB näher eingegangen. Bei der Verwaltung der Benutzer wird folgendermaßen vorgegangen. Ein Benutzer will sich bei der LDB anmelden. Dazu schickt er das Kommando LOGON an die LDB. Das LDB-Serverprogramm prüft, ob die UNIX-Rechte des Benutzers (Benutzer- und Gruppen-Status) dem Benutzer besondere Rechte in der LDB einräumen. Dazu wird der Benutzer einer der drei LDB-Benutzergruppen (Root, privilegiert, normal) zugeordnet. Dann wird der Benutzer in die LDBBenutzertabelle eingetragen. Nun kann der Benutzer Dienste der LDB – entsprechend seiner Rechte – in Anspruch nehmen. Am Ende seiner Arbeit mit der LDB muß er sich durch das Kommando LOGOFF von der LDB abmelden. Sein Eintrag in der Benutzertabelle wird entfernt. Zuvor werden alle Sperrungen von Datensätzen gelöscht, die der Benutzer möglicherweise während seiner Arbeit mit der LDB vorgenommen hat. Soll für einen Benutzer die Verbindung zur LDB, die durch den Eintrag in der Benutzertabelle dokumentiert wird, abgebrochen werden, hat ein Root-Benutzer die Möglichkeit, über den Befehl KILL diesen Benutzer aus der Benutzertabelle zu entfernen. Dies kann dann nötig sein, wenn z.B. der Benutzerprozeß beendet wird, ohne daß der Benutzer sich bei der LDB abmelden konnte. Die Benutzertabelle wird von vielen Funktionen der LDB benutzt, z.B. für das Sperren von Datensätzen, für die Überwachung der Schreibberechtigung von Benutzern, etc. Deshalb sind der aktuelle Benutzer und ein Verweis auf die Benutzertabelle global in der LDB verfügbar. 6.3.5 Fehlerbehandlung Zu jedem Zeitpunkt können Fehler in der LDB auftreten. Die potentiellen Fehlerquellen sind zahlreich. [11] nennen folgende für Datenbanken relevante Fehlerkategorien: KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 83 1. Rechnerfehler (Hardware-, Software-, Firmwarefehler) 2. Verarbeitungsfehler während einer Transaktion 3. Lokale Abbruchbedingungen 4. Fehler, die durch die Wahrung des gegenseitigen Ausschlusses entstehen 5. Medienfehler (Fehler auf der Festplatte oder dem Netzwerk) 6. Physikalische Fehler und Katastrophen: “This is an endless list that includes power [...] failure, fire, theft, sabotage [...]”23 Die Fehler der Kategorie 1, 5 und 6 sind nur schwer faßbar. Im übrigen sind diese Arten von Fehlern eher selten. Sie sind am besten durch ein sinnvolles BackupKonzept, wie es in jedem Rechnersystem betrieben werden sollte, mit geringen Verlusten zu meistern. Die LDB beschäftigt sich hauptsächlich mit den Fehlern der Kategorien 2, 3 und 4. Wenn in einem Programm Fehlerklassen unterschieden werden, ist dies am einfachsten durch die Unterscheidung kritischer Fehler von einfachen Fehlern. Kritische Fehler sind solche, die u.U. die Integrität der Daten oder sogar deren Existenz gefährden. Ziel einer jeden Fehlerbehandlung ist es, den Fehlerzustand zu erkennen, die Art des Fehlers zu bestimmen, das Programm in einen sicheren und definierten Betriebszustand zu bringen und den Benutzer vom Auftreten der Fehlersituation mit möglichst umfangreicher Information zu dem Fehler, seinen Ursachen und evtl. Wegen zur Behebung der Fehlerursachen zu verständigen. Die Fehlerbehandlung wird entweder im Quelltext an den entsprechenden Stellen oder zentral durch ein eigenes Modul vorgenommen. Für die Implementation der LDB wurde der zweite Weg gewählt. Diese Lösung ergibt sich vor allem durch die besondere Problematik der RPCs (vgl. Abschnitt 7.2.2) und aus der Tatsache, daß der verarbeitende Programmteil vom steuernden Programmteil getrennt ist. In der LDB werden erkannte Fehlerzustände mit einem Zahlencode bezeichnet. Für jeden Zahlencode existiert im Fehlerbehandlungsmodul eine Fehlermeldung, so daß der Fehlerzustand dem Benutzer sowohl als Zahlencode als auch als Klartextmeldung bekanntgemacht werden kann. 23 [11], S. 540 KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 84 Damit keine Umsetzung von Fehlercodes des Servers24 in Client-Fehlercodes vorgenommen werden muß, verwenden Server und Client das gleiche Quelltextmodul zur Fehlerbehandlung. Für den Client werden zusätzliche Fehlermeldungen benötigt, um Fehlerzustände im Clientprogramm zu beschreiben. Diese ClientFehlercodes werden in einen Zahlenbereich abgebildet (Fehlercodes > 300), der außerhalb dem des Servers ist (Fehlercodes < 200). Die Fehlercodes werden dem Benutzer anstelle des Ergebnisses der jeweiligen Anfrage übergeben. Im Client-Programm wird dann die zum Fehlercode passende Klartextfehlermeldung ausgegeben. Die datenverändernden Funktionen der LDB sind so gestaltet, daß der Moment der Zustandsänderung der LDB möglichst kurz und damit potentiell wenig fehlerträchtig ist. Da der Programmablauf nach einem aufgetretenen Fehler wieder in die zentrale Serverfunktion zurückkehrt, befindet sich die LDB nach (erfolgreichem oder fehlerhaftem) Abschluß einer Transaktion25 immer in einem definierten Zustand. Die Behandlung von Fehlern, die in den externen Filterprogrammen auftreten gestaltet sich schwieriger, da diese keinen Fehlercode übermitteln, sondern eine Klartextfehlermeldung. Damit diese dem Benutzer zugänglich gemacht werden kann, wird sie in einem Puffer zwischengespeichert. So kann der Benutzer, der durch die LDB verständigt wird, daß ein Filterprogrammfehler aufgetreten ist, mit Hilfe einerr Anfrage an die LDB sich diese Klartextfehlermeldung des Filterprogramms zuschicken lassen. Kritische Fehler können von Anwendungsprogrammen nur sehr unzureichend behandelt werden, zumal wenn die Fehler auf einer sehr niedrigen Systemebene auftreten. Obwohl es unmöglich ist, alle Fehlersituationen vorherzusehen und programmseitig abzufangen, versucht die LDB durch ein zeitgesteuertes Sichern der Dateipuffer von Indexbaum-Cache, Schlüsselsatzpuffer und Indextabelle die Möglichkeit eines totalen Datenverlustes gering zu halten. Die Zeitdauer, nach der ein solches Sichern erfolgt ist in den Definitionsdateien des Quelltexts festgelegt. Zu Beginn der ersten Benutzeranfrage nach Ablauf der eingestellten Zeitspanne bzw. nach einer maximalen Anzahl datenverändernder Benutzeranfragen schreibt die LDB oben genannte Daten in den Hintergrundspeicher. Zusätzlich fängt das LDB-Serverprogramm bestimmte Systemsignale ab, um einen geregelten Servershutdown durchzuführen26 . 24 Die Begriffe Server und Client werden in Abschnitt 7.1 vorgestellt. Begriff der Transaktion vgl. Abschnitt 4.5.1. 26 Dies wird ausführlicher in Abschnitt 8.2.1 behandelt. 25 Zum KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 85 Wird das LDB-Serverprogramm als Hintergrundprozeß gestartet, werden seine Fehlerausgaben, die sonst auf die Standardfehlerausgabe der Servershell erfolgen, in eine Protokolldatei abgelegt, die der Datenbankverwalter nach einer rätselhaften Beendigung des LDB-Serverprogramms zur Fehleranalyse einsehen kann. Beim Einlesen von Lexikoneinträgen aus einer Datei wird ebenfalls eine Protokolldatei verwendet, um dem Benutzer mitzuteilen, welche Einträge schon in der LDB vorhanden waren bzw. wenn ein neuer Eintrag sich mit einem schon existierenden einen Suchschlüssel teilt. Diese Protokolldatei hält auch auftretende Fehler fest und wird in einem durch den Benutzer angegebenen Verzeichnispfad abgelegt. 6.4 Der Umgang der Lexikondatenbank mit Speicherressourcen Die LDB erzeugt neben den bereits vorhandenen, vom Benutzer eingegebenen Daten des Grundformlexikons zusätzliche Daten. Im nächsten Abschnitt soll erfaßt werden, welche Daten zusätzlich erzeugt werden und wie die Größe der Verwaltungsstrukturen der LDB in der Gesamtspeicherbilanz niederschlagen. Danach wird über Ansätze zur Komprimierung der Datensätze nachgedacht. 6.4.1 Speicherplatzbedarf der Datenbankdaten Die gesamte durch die LDB verwaltete und erzeugte Datenmenge setzt sich aus folgenden Teildatenmengen zusammen: 1. Daten des Grundformlexikons 2. Daten des Allomorphlexikons 3. Daten der Paradigmentabelle 4. Daten des Kommentarlexikons 5. Daten der Indextabelle 6. Daten der Indexbäume 7. Daten der Schlüsselsätze KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 86 Alle Daten außer denen in 1., 2. und zum Teil 4. sind LDB-spezifisch, d.h. werden erst durch den Betrieb der LDB erzeugt. 6.4.1.1 B EDARF AN H INTERGRUNDSPEICHER Im folgenden soll das Datenaufkommen anhand des aktuellen Lexikons der deutschen Sprache mit ca. 20000 Grundformeinträgen betrachtet werden. Die Angaben zum Speicherplatzbedarf bedeuten dabei immer Speicherplatzbedarf im Hintergrundspeicher. Der Gesamtspeicherplatzverbrauch des o.g. Lexikons beträgt ca. 13.6 MByte27 . Der Wert schlüsselt sich wie in Tabelle 6.1 gezeigt auf. Modul Grundformen Allomorphe Paradigmentabelle Kommentare Indextabelle Gesamt Anzahl Einträge 20.235 26.534 20.234 20.235 Speicherbedarf 3.361.128 Byte 5.995.095 Byte 1.964.575 Byte 2.092.507 Byte 213.948 Byte 13.627.275 Byte Anteil an LDB 24,6 % 44,0 % 14,4 % 15,4 % 1,6 % 100,0 % Tabelle 6.1: Speicherbedarf der einzelnen Teildatenbanken der LDB In Tabelle 6.2 soll stellvertretend für die anderen Teildatenbanken der LDB die Aufgliederung des Speicherbedarfs auf die Komponenten Datensätze, Schlüsselsätze und Indexbaum im Grundform-Modul demonstriert werden. Komponente Datensätze Schlüsselsätze Indexbaum Headerblock Gesamt Speicherbedarf 1956923 Byte 1050240 Byte 353945 Byte 20 Byte 3.361.128 Byte Anteil 58,2 % 31,3 % 10,5 % < 0,1 % 100,0 % Tabelle 6.2: Speicherbedarf der Komponenten einer Teildatenbank Bei der hier gezeigten Teildatenbank stehen Verwaltungsinformation und verwaltete Information zueinander im Verhältnis 1:2,39. 27 Dieser Wert wurde direkt nach dem Einlesen der derzeit vorhandenen Lexikondateien gemessen. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 87 Diese Zahlen, die für sich alleine erst einmal sehr groß erscheinen, sind mit dem Datenaufkommen des Lexikons, wenn es nicht über die LDB verwaltet wird, in Beziehung zu setzen. Tabelle 6.3 zeigt den Speicherbedarf eines auf Dateibasis verwalteten Lexikons. Datei Grundformlexikon Allomorphlexikon Gesamt Anzahl Einträge 20.235 Speicherbedarf 2.908.873 Byte 2.973.147 Byte 5.882.020 Byte Anteil an Gesamt 50,5 % 49,5 % 100,0 % Tabelle 6.3: Speicherbedarf der Lexikondaten ohne die LDB Im Gegensatz zur LDB, in der die Größe von Grundformlexikon und Allomorphlexikon sehr unterschiedlich ist, stimmt diese Größe beim bisherigen Vorliegen des Lexikons fast überein. In der LDB werden die Kommentare, die in der bisherigen Form im Grundformlexikon stehen, im Kommentarmodul behandelt und belasten somit nicht mehr das Speicherkonto des Grundformlexikons. Zudem sind durch die syntaktische Überprüfung im Eingabe-Filtermodul des Grundformlexikons alle überflüssigen Leer- und Steuerzeichen aus dem Grundformlexikon entfernt worden, also auch Einrückungen, Zeilenumbrüche, usw. Andererseits liegen die Basiszeichenketten in der LDB getrennt von den Allomorpheinträgen in der Paradigmentabelle bzw. in der Indextabelle. In der bisherigen Form werden sie zusammen mit den Allomorphen gespeichert. Ein Überwiegen der Allomorphe erklärt sich noch aus einem anderen, linguistischen Grund. Durch die Allomorphgenerierung werden immer gleichviele oder mehr Allomorpheinträge zu jedem Grundformeintrag generiert. Da der Allomorphie-Quotient im deutschen Lexikon bei ca. 20-25 % liegt, ist also dieser Zuwachs an Speicherplatz in den Vergleich miteinzubeziehen. Wie sieht letztlich das Verhältnis zwischen den Speicherplatzbedürfnissen des reinen, dateigestützten Lexikons und des Lexikons in der LDB aus? Tabelle 6.4 stellt die beiden Gesamtergebnisse der beiden vorigen Tabellen einander gegenüber. Repräsentation Lexikon in Dateien Lexikon in der LDB Speicherbedarf 5.882.020 Byte 13.627.275 Byte Faktor 1 2,32 Tabelle 6.4: Gegenüberstellung des Speicherplatzbedarfs KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 88 Das Speicheraufkommen bei Verwaltung des Lexikons über eine Datenbank ist also 1,3 mal höher als bei der Verwaltung in Dateien, wie es ähnlich schon aus der Anmerkung zu Tabelle 6.2 hervorgeht. Dieser an sich ausgezeichnete Wert ist jedoch etwas zu relativieren. 6.4.1.1.1 Schwache Fragmentierung Wie in Abschnitt 5.4.2 schon erklärt wurde, wird die LDB während ihrer Laufzeit fragmentieren, wenn Lexikoneinträge modifiziert oder gelöscht und neue eingefügt werden. Diese Art der Fragmentierung soll als schwache Fragmentierung bezeichnet werden. Sie tritt auf, wenn die LDB zur Wartung bereits eingelesener Einträge (d.h. ohne größere Dateioperationen) betrieben wird. Messungen zur Fragmentierung durchzuführen, die zumindest einigermaßen den Bedingungen im realen Betrieb der LDB nahekommen, ist sehr schwierig. Mangels einer vernünftigen Versuchsbasis soll hier nur eine kurze Überschlagsrechnung durchgeführt werden. Wie im nächsten Abschnitt noch zu sehen sein wird, gibt es nur wenige sehr lange Lexikoneinträge. Die Durchschnittslänge der Einträge des Verblexikons liegt bei 200 Byte pro Lexikoneintrag. Für die Rechnung soll angenommen werden, daß während einer Betriebssitzung mit der LDB 300 Lexikoneinträge geändert werden, und zwar so, daß die LDB fragmentieren muß. Das heißt, daß die angenommenen 300 Einträge zuerst gelöscht und dann neu eingetragen werden. Dies geschieht bei jeder replace-Operation. Für jede Einfügeoperation wird ein neuer Schlüsselsatz abgespeichert. Aus Tabelle 6.2 läßt sich folgern, daß ein einzelner Schlüsselsatz durchschnittlich 52 Byte lang ist. Eine Indexseite mit zur Zeit 100 Elementen ist mit einer Länge von ca. 1200 Byte zu berücksichtigen. Der sich nach den o.g. Operationen ergebende Zusatzspeicherbedarf der LDB errechnet sich für das Grundform-Modul dann folgendermaßen: Zusatzbedar f = 300 * Länge eines Lexikoneintrags + 300 * Länge eines Schlüsselsatzes + 2 * Größe einer Indexseite. Für unser Beispiel ergibt dies einen Mehrbedarf gegenüber dem Startbedarf von ca. 78.000 Byte. Dieser Wert macht nicht einmal 3 Prozent der Gesamtgröße des Grundform-Moduls aus. Die Verluste durch schwache Fragmentierung können also mit Recht als geringfügig bezeichnet werden. Für die anderen Teildatenbanken können diese Werte im allgemeinen prozentual übernommen werden. Eine Ausnahme bildet das Allomorph-Modul, da es durch KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 89 die Allomorphgenerierung mehr Fragmentierungspotential aufweist als die anderen Module. 6.4.1.1.2 Massive Fragmentierung Das mit Tabelle 6.1 angeführte Beispiel beschreibt ein Lexikon, das aus Dateien eingelesen wurde. An diesem Lexikon wurden nach dem Einlesen keine Veränderungen durchgeführt, so daß auf den ersten Blick keine (schwache) Fragmentierung vorzuliegen scheint. Dennoch erstaunt die aus den übrigen Werten herausragende Größe des Allomorph-Moduls, das beinahe doppelt so groß ist wie das GrundformModul. Die Größe scheint umso unerklärlicher, als im Allomorph-Modul die Basiszeichenketten nicht mehr enthalten sind und in den Datensätzen des AllomorphModuls Binärcode liegen sollte, der im allgemeinen sehr kompakt ist. Ein Blick in die Übersichtsinformation des LDB-Serverprogramms zur aktuellen Datenbank zeigt die Lösung dieses Widerspruchs in Form der Angabe zur maximalen Anzahl der Unterschlüssel in den Schlüsselsätzen (mset). MODULE: ’allomorph lexicon’: keys 24283 sets 26534 mset 5 Da keine Aussage gemacht wird, wieviele Schlüsselsätze die maximale Anzahl an Unterschlüsseln besitzt, können hier nur qualitative Aussagen gemacht werden. Wenn man annimmt, daß beim Einlesen einer Lexikondatei in die LDB wie im Beispiel ersichtlich nacheinander 5 Grundformeinträge mit verschiedenen Oberflächen (also Grundformschlüsseln) gelesen werden, aus denen aber zufällig fünf in der Allomorphoberfläche identische Allomorpheinträge generiert werden, so wird der betreffende Schlüsselsatz vier mal mit wachsender Größe ans Ende der Schlüsselsatzdatei umkopiert. Sein Speicherbedarf verfünffacht sich also. Wenn nun genügend Allomorpheinträge mehr als einen oder zwei Unterschlüssel haben, dann läßt sich zumindest die Größenordnung des rapiden Anwachsens der Dateien erklären. Die Fragmentierung, die beim Einlesen von Dateien in die LDB entsteht, also ohne Löschungen oder Ersetzungsvorgänge, soll mit massiver Fragmentierung bezeichnet werden. Um die Folgen der massiven Fragmentierung zu minimieren empfiehlt es sich demnach, nach dem Einlesen größerer Dateien in die LDB eine Defragmentierung durchzuführen. Dies wurde auch für das genannte Beispiel durchgeführt. Die Ergebnisse sind in Tabelle 6.5 zu sehen. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK Modul Grundformen Allomorphe Paradigmentabelle Kommentare Indextabelle Gesamt Anzahl Einträge 20.235 26.534 20.234 20.235 Speicherbedarf 3.245.052 Byte 3.024.551 Byte 1.849.194 Byte 1.976.192 Byte 213.948 Byte 10.308.937 Byte 90 Anteil an LDB 31,5 % 29,3 % 17,9 % 19,2 % 2,1 % 100,0 % Tabelle 6.5: Speicherbedarf der Lexikondatenbank nach dem Defragmentieren Die Defragmentierung hatte ihren größten Effekt auf die Größe des AllomorphModuls, welches auf fast exakt die Hälfte (50,5 %) verkleinert werden konnte. Wenn ein starker Anwachsen des Speicherbedarfs auf massive Fragmentierung zurückgeht, wird sich die Defragmentierung sehr positiv auf den Speicherbedarf auswirken. (im Gegensatz zur schwachen Fragmentierung). Das Verhältnis von Nutzdaten zu Verwaltungsdaten kann so erheblich verbessert werden, im obigen Beispiel auf etwa 1:1,75 ! 6.4.1.2 B EDARF AN VORDERGRUNDSPEICHER In den Abschnitten über den Aufbau der Teildatenbanken (Abschnitt 5.3ff) wird darauf hingewiesen, daß sowohl ein großer Teil des Indexbaums als auch die gesamte Schlüsselsatzdatei im Vordergrundspeicher gepuffert werden. Dazukommen die Indextabelle, die Benutzertabelle und die Sperrtabelle. In den nächsten Absätzen soll der ungefähre Vordergrundspeicherbedarf der laufenden LDB errechnet werden. In Tabelle 6.6 wird eine Gesamtbilanz des verwendeten Vordergrundspeichers erstellt. Dabei werden die größeren Werte aus Tabelle 6.1 verwendet, da sie eine Art realen Worst-Case darstellen. Der von den externen Filterprogrammen benötigte Vordergrundspeicher wurde hier nicht in Erwägung gezogen, weil die Filterprogramme nicht Teil der LDB sind. Auffällig ist der Verbrauch von Vordergrundspeicher für die Pufferung der Schlüsselsatzdateien. Es ist denkbar, daß die zur Zeit vollständig im Vordergrundspeicher gepufferten Schlüsselsatzdateien in Zukunft über den UNIX-FileMapping-Mechanismus in den Vordergrundspeicher abgebildet werden. Dadurch würde die Kontrolle dem Betriebssystem übergeben, das je nach Anforderungen anderer Prozesse den Speicher für die Schlüsselsätze dynamisch zuweisen könnte. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK Modul Grundform Allomorph Paradigmentabelle Kommentar LDB Gesamt Komponente Indexbaum-Cache Schlüsselsätze Sperrtabelle sonstige ca. Indexbaum-Cache Schlüsselsätze sonstige ca. Indexbaum-Cache Schlüsselsätze sonstige ca. Indexbaum-Cache Schlüsselsätze sonstige ca. Indextabelle Benutzertabelle sonstige ca. LDB Programm Speicherbedarf 76.800 Byte 1.050.240 Byte 1.200 Byte 2.000 Byte 76.800 Byte 4.196.192 Byte 2.000 Byte 76.800 Byte 1.050.274 Byte 2.000 Byte 76.800 Byte 1.050.368 Byte 2.000 Byte 216.000 Byte 11.200 Byte 20.000 Byte 190.000 Byte 8.100.674 Byte 91 Anteil an Gesamt 1,0 % 13,0 % < 0,1 % < 0,1 % 1,0 % 51,7 % < 0,1 % 1,0 % 13,0 % < 0,1 % 1,0 % 13,0 % < 0,1 % 2,6 % 0,1 % 0,3 % % 2,3 % 100 % Tabelle 6.6: Gesamtbedarf der LDB an Vordergrundspeicher KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 92 Ein File-Mapping wurde nicht implementiert, da der schreibende Zugriff auf eine gemappte Datei unter POSIX nicht definiert ist. Diese Erweiterung sollte jedoch mit überschaubarem Aufwand implementierbar sein, zumal in der LDB die Pufferung von Dateien sehr allgemeingültig in einem eigenen Quelltextmodul und über genau definierte Schnittstellen vorgenommen wird. Die Schnittstellenfunktionen verhalten sich dabei genau wie die C-Bibliotheksfunktionen für gepuffertes Lesen und Schreiben auf einen Stream (z.B. fopen, fread, etc.). Wenn keine Datenbank geöffnet ist, benötigt das LDB-Serverprogramm ldb ca. 230 KByte Vordergrundspeicher. 6.4.2 Komprimierung der Datensätze Wenn auch im vorhergehenden Abschnitt gezeigt wurde, daß sich die Speicherbedarfentwicklung durch schwache Fragmentierung auf einem sehr niedrigen Niveau bewegt, kam dennoch angesichts der fragmentierenden Schlüsselsatzdatei und Datensatzdatei schon früh im Verlauf dieser Arbeit der Gedanke auf, den Inhalt der Datensätze zu komprimieren. Dies ist weniger als Maßnahme gegen das Fragmentieren denn als eine generelle Maßnahme zu sehen, um den Speicherbedarf der Datensätze zu reduzieren. Zur Komprimierung von Daten existieren verschiedene Algorithmen. Die meisten praktisch unter UNIX eingesetzten Kompressionsprogramme (z.B. GZIP, COMPRESS) arbeiten auf einer statistischen Basis. Sie untersuchen den Inhalt der zu komprimierenden Dateien, indem sie nach immer wiederkehrenden Byte-Mustern suchen. Dann ersetzen sie alle weiteren Vorkommen des Musters durch Verweise auf das erste Vorkommen. Die Ersetzungen erfolgen blockweise, am Anfang eines Blocks werden in einem Header Informationen über den Block gespeichert. So sind Komprimierungsraten von 10 % der Originalgröße und weniger (z.B. bei Bilddateien) zu erzielen. Um die Tauglichkeit einer solchen, allgemeingültigen Komprimierung auszuwerten, wurden an einem repräsentativen Ausschnitt einer Lexikondatei Messungen durchgeführt. Diese Messungen sollten eine Antwort auf die Frage geben, ob eine eintragsbezogene Komprimierung der Datensatzdatei sinnvoll und effizient ist. Dazu wurde aus dem Verblexikon (5385 Einträge) jeweils ein Eintrag herausgenommen, mit dem UNIX-Programm GZIP28 komprimiert und in einer Ergebnisdatei abgelegt. Nach Abarbeiten aller Einträge des Verblexikons befanden sich alle 28 [35], [37] KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 93 Lexikoneinträge des Ausgangslexikons eintragsweise komprimiert in der Ergebnisdatei. Verglichen wurde diese Größe der Ergebnisdatei zum einen mit der als ganzes komprimierten Verblexikondatei und einer Datei, die vom Allomorphgenerator MALAGAs (MALLEX) komprimiert worden war. Datei: Anzahl der Einträge: Größe unkomprimiert: Größe eintragsweise komprimiert: Größe dateiweise komprimiert: Größe mit MALLEX komprimiert: verb.lex 5.385 Einträge 1.077.817 Byte 672.521 Byte 48.102 Byte ca. 380.000 Byte prozentuale Größe nach Kompression Tabelle 6.7: Größe der Lexikondatei vor und nach dem Komprimieren Die in Tabelle 6.7 dargestellten Ergebnisse für die eintragsweise Komprimierung scheinen ein sehr ungünstiges Kompressionsverhältnis im Vergleich mit denen der dateiweisen Komprimierung zu ergeben. Um eine Erklärung für diese Werte zu finden, wurde die Länge der Einträge des Verblexikons im einzelnen gemessen. Die Ergebnisse dieser Messung werden in Tabelle 6.8 gezeigt. Kürzester Eintrag: Längster Eintrag: Durchschnittl. Länge: 83 Byte 5.975 Byte 200 Byte Tabelle 6.8: Ergebnisse der Analyse der Eintragslängen Man sieht, daß die Einträge des Verblexikons sehr unterschiedlich lang sein können. Eine viel wichtigere Beobachtung ist aber, daß die Anzahl der Einträge, deren Länge zwischen 165 und 180 Byte beträgt, 12,11 % aller Einträge ausmacht. Die Anzahl der Einträge, deren Länge zwischen 88 und 103 Byte beträgt macht sogar 65,22 % aller Einträge aus. Das bedeutet, daß ca. drei Viertel aller Einträge sehr kurz sind und nur sehr wenige sehr lang. Nach diesen Messungen wurden Versuche mit der Komprimierung einzelner Einträge gemacht. Dabei stellte sich heraus, daß sich lange Einträge sehr gut kom- 100 % 62,4 % 4,5 % ca. 35 % KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 94 primieren lassen. Der Lexikoneintrag für z.B. fahren mit 5147 Byte Originalgröße läßt sich auf 485 Byte komprimieren, was 9,42 % entspricht. Doch gerade die kürzesten Einträge werden im allgemeinen durch die Komprimierung länger, wie z.B. der Eintrag für adeln mit 83 Byte Länge zeigt, der komprimiert eine Länge von 98 Byte hat. Die Begründung dafür findet sich in der schon angesprochenen Arbeitsweise von GZIP, das für jeden zu komprimierenden Datenbereich einen Header anlegt. Scheinbar brauchen die Header bei Einträgen unter ca. 130 Byte Länge mehr Speicherplatz als die Gewinne durch die Kompression einbringen. Da die kürzesten Einträge einen sehr großen Anteil des Lexikons ausmachen, gleicht der für ihre Header und Verwaltungsstrukturen verwendete Platz die Gewinne an Speicherplatz, die die Kompression der langen Einträge erzielt, zu großen Teilen aus. Im übrigen lag die für die eintragsweise Komprimierung benötigte Zeitspanne bei ca. 5 Minuten (C-Programm mit Aufruf des GZIP über einen Systemaufruf) bis zu ca. 15 Minuten (ELisP-Programm mit Aufruf des GZIP über einen Systemaufruf). Bei einer Integration des Lempel-Ziv-Algorithmus in die Zugriffsstruktur der Datenbank würden hier sicher hohe Laufzeitgewinne zu erzielen sein. Ein einfacher Ansatz wie in der beschriebenen Versuchsanordnung ist jedoch nicht mit dem Ziel schneller Zugriffe auf die Datenbank zu vereinbaren. Eine aus Speicherplatzsicht sehr vorteilhafte Komprimierung der gesamten Datensatzdatei verbietet sich deswegen, weil dann nicht mehr ohne vorherige Dekomprimierung direkt auf sie zugegriffen werden könnte. Als Alternative bleibt die inhaltsbezogene Komprimierung z.B. mit MALLEX (oder MALFIL). Die dabei erzielte Kompressionsrate von ca. 35 % ist akzeptabel. Auch die Ausführungsgeschwindigkeit der Komprimierung bleibt in einem der Anwendung angemessenen Rahmen, wird doch die Komprimierung schon jedesmal bei der Kompilation der Allomorphe durchgeführt. Dennoch würde die Komprimierung mit Hilfe von Allomorphregeln nicht ausreichen. Mit dieser Methode würden z.B. Präfix-Oberflächenzeichenketten, die gerade bei den Verblexikoneinträgen einen großen Anteil am aufgewendeten Speicherplatz ausmachen und zugleich eine hohe Redundanz aufweisen, nicht komprimiert werden. Eine andere Methode der inhaltsbezogenen Komprimierung ist eine stark linguistisch motivierte. Beim Betrachten des Lexikons ist es auffällig, daß bestimmte Muster in der kategorialen Beschreibung vieler Lexikoneinträge häufig wiederkehren. Sie unterscheiden sich meist nur durch die Oberflächenzeichenkette. Hier wäre KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 95 ein Modul denkbar, das solche Muster auffindet, in einer Schablonendatei explizit macht und dementsprechend den Inhalt der Lexikoneinträge komprimiert. Dieses Verfahren kann so weiterentwickelt werden, daß der Lexikonbearbeiter selbst das Lexikon schon in Form dieser Schablonen definiert und nur noch die variablen oder abweichenden Teile des neuen Lexikoneintrags explizit in diesem ausführt. Dazu müßte jedoch die Beschreibung und Strukturierung des Lexikons grundlegend verändert werden. KAPITEL 6. DIE IMPLEMENTATION DER LEXIKONDATENBANK 96 Puffer initialisieren Grundformschlüssel Grundformeintrag SF-Attribut Grundformeintrag filtern Existiert identischer Eintrag? Beenden ja nein Allomorphe generieren Paradigmeneintrag suchen Allomorphoberfläche Allomorpheinträge Basiszeichenketten Bestehender Paradigmeneintrag oder Leerer Paradigmeneintrag Grundformeintrag speichern Aufbau der Verzeigerung Allomorphe speichern zwischen Grundform- und Paradigmeneintrag Allomorph-Grundform-Tupel in Paradigmentabelle eintragen zwischen Allomorpheinträgen und Paradigmeneintrag Paradigmeneintrag speichern Verzeigerungen abspeichern Abbildung 6.11: Skizziertes Flußdiagramm der Funktion addEditEntry. Auf der rechten Seite der Abbildung werden die Ergebnisse des betreffenden Schritts angegeben. Kapitel 7 Netzwerkkommunikation Alle bisherigen Überlegungen bezogen sich auf die LDB als eine abgeschlossene Einheit, von der nur das Innere betrachtet wurde. Im folgenden soll eines der Ziele dieser Arbeit, die gleichzeitige Arbeit mehrerer Benutzer an der LDB in den Mittelpunkt gerückt werden. Zuerst wird beschrieben, welche Strukturen es ermöglichen, daß mehrere Benutzer gleichzeitig an einem Rechner in einem Netzwerk arbeiten können und Dienste eines Programmes von einem anderen Rechner aus in Anspruch nehmen können. Danach werden Wege erklärt, wie diese Kommunikation auf der Programmebene abläuft. Zu Ende des Kapitels soll auf die Realisierung dieser Konzepte in der LDB eingegangen werden. 7.1 Das Client-Server-Konzept Wenn mehrere Rechner auf gemeinsame Daten zugreifen sollen, werden sie über ein Netzwerk verbunden. Auf der Hardwareebene gibt es verschiedene Netzwerkstrukturen (z.B. sternförmig, netzförmig, ringförmig, etc.), auf die aber hier nicht näher eingegangen werden soll1 . Eine wichtige Grundlage solcher Netzwerke sind Mechanismen und Strukturen, mit denen vermieden wird, daß die verschiedenen Rechner sich gegenseitig während ihrer Tätigkeiten im Netzwerk beeinträchtigen. Dies würde dann geschehen, wenn zum Beispiel alle Rechner gleichzeitig auf bestimmte Ressour1 Die verschiedenen Netzwerktopologien werden ausführlich bei [20], S. 286ff vorgestellt. 97 KAPITEL 7. NETZWERKKOMMUNIKATION 98 cen zugreifen wollten. Um eine Art Verkehrsregelung im Netzwerk vorzunehmen, werden bestimmte, höherberechtigte Rechner gegenüber den anderen Rechnern ausgezeichnet. Diese zentralen Rechner haben meist mehr Speicherplatz (sowohl Vordergrund- als auch Hintergrundspeicher) zur Verfügung und verwalten die Zugriffe und Anfragen der anderen Rechner im Netzwerk. Solche Rechner, die die anderen “bedienen”, nennt man Server, die anderen Rechner Clients. Kleine Rechnernetzwerke (Cluster) können Subnetze (Subdomäne) größerer Netzwerke (Domänen) sein, die wiederum ihre Server-Rechner zur Koordinierung haben. Das Client-Server-Konzept kann man sich als eine sternförmige Struktur vorstellen, mit deren Hilfe die an den Strahlenenden liegenden Clients Dienste des im Zentrum liegenden Servers anfordern und, so sie die Berechtigung dazu haben, sie diese Dienste zugeteilt bekommen. Diese logische Sternform (Abbildung 7.1) ist unabhängig von der vorliegenden Hardwarestruktur. Client Client Server Client Client Abbildung 7.1: Das Client-Server-Konzept Mit Hilfe des Client-Server-Konzepts ist es also möglich, daß zentrale Ressourcen (wie z.B. eine Datenbank, Druck- und Maildienste) so verwaltet werden, daß mehrere entfernte Benutzer Zugriff darauf haben. Entfernte Benutzer können sowohl im selben Cluster als auch tatsächlich räumlich entfernt (z.B. in einer anderen Domäne) angesiedelt sein. Folgende Schritte werden nacheinander ausgeführt, wenn eine Client-ServerAnwendung benutzt werden soll: Ein Serverprozeß wird gestartet. Er initialisiert seine Daten, die Netzwerk- KAPITEL 7. NETZWERKKOMMUNIKATION 99 schnittstelle und die Kommunikationsprotokolle. Der Serverprozeß geht nach erfolgreicher Initialisierung in den Wartezustand. Ein Clientprozeß wird auf einem beliebigen Rechner im Netzwerk gestartet. Nach seiner Initialisierung versucht er, Verbindung zum Serverprozeß auf dem Server-Rechner aufzunehmen. Nach erfolgreicher Kontaktaufnahme kommunizieren Client und Server gemäß des vereinbarten Protokolls. Dabei führt der Server einen vom Client beanspruchten Dienst aus. Nachdem der Dienst vom Server ausgeführt wurde und die etwaigen Ergebnisse dem Client zurückgeliefert wurden, geht der Server wieder in den Wartezustand, um auf erneute Anfragen von Clients reagieren zu können. KAPITEL 7. NETZWERKKOMMUNIKATION 100 Bei den Servern unterscheidet man zwei Arten: iterative Server, die Dienste für den Client in absehbarer Zeit selbst erledigen können. [34] führt als typischen Vertreter dieser iterativen Art [...] den Server-Prozeß, der die Systemzeit liefert”2 , an. parallele (concurrent) Server, die Dienste erledigen, deren Gesamtlaufzeit nicht absehbar ist, und die diese Dienste von Unterprozessen ausführen lassen. Nach Starten des Unterprozesses stehen sie den Clients wieder zur Verfügung, während der Unterprozeß die letzte Anfrage des Clients noch zu Ende bearbeitet. Client und Server müssen dazu eine gemeinsame Schnittstelle haben. Die Schnittstelle beschreibt den Übergabemechanismus für Daten und Anweisungen. Natürlich muß der Client informiert sein, welche Dienste ihm der Server anbieten kann. Da beim Client-Server-Konzept Client und Server weit voneinander entfernt sein können, ist es notwendig, die Schnittstelle zwischen beiden einerseits flexibel zu gestalten, um die Datenübertragung und die Verwendung der Daten auf verschiedensten Rechnern abwickeln zu können. Andererseits muß die Kommunikation exakt definiert werden, damit keine “Mißverständnisse” zwischen Client und Server vorkommen. Um dieser Anforderung gerecht zu werden, definiert man ein Kommunikationsprotokoll. Kommunikationsprotokolle können sowohl softwareals auch hardwaremäßig realisiert werden. Neben den reinen Dienstleistungen des Servers muß dieser dem Client auch Auskunfts- und Diagnosedienste zur Verfügung stellen. Die Auskunftsdienste umfassen z.B. Informationen über die Auslastung des Servers, über die vom Server benutzten Ressourcen oder einfach auch eine Liste der Serverdienste. Die Diagnosedienste ermöglichen es dem Client, unerwartete Fehler im Server (fehlende Ressourcen, Abarbeitungsfehler), die ihn betreffen, zu erklären, so daß entweder der Server auf Veranlassung des Clients diese beheben kann, oder daß der Client dies selbst tun kann. Eine weitere wichtige Aufgabe des Servers ist die Verwaltung der Clients und der Verbindungen zu diesen. Für die Aufgabenstellung der vorliegenden Arbeit erweist sich das Client-ServerKonzept, wie in Abbildung 7.2 nochmals zusammenfassend dargestellt, als sehr gut geeignet. Die Aufgabenstellung, mehreren Benutzern quasi-gleichzeitigen Zugriff auf ein zentrales Lexikon zu geben, dabei aber auch ihre Zugriffsrechte überprüfen zu können, entspricht ziemlich genau den Merkmalen des Client-Server-Konzepts. 2 [34], S. 6 KAPITEL 7. NETZWERKKOMMUNIKATION Client 101 Überwachung des Protokolls Überprüfen der Zugriffsrechte Client Verwalten der Verbindungen ServerDienste Verwalten der Clients Client Exklusiver Zugriff auf Dienste Abbildung 7.2: Client-Server-Konzept mit Zugangsregelung 7.2 Strukturen für die Netzwerkkommunikation Wie aus dem vorigen ersichtlich wird, ist das Client-Server-Konzept auf ein funktionierendes Netzwerk angewiesen, das die einzelnen Clients mit dem Server physikalisch verbindet. 7.2.1 Das ISO-OSI-7-Schichten-Modell Für die Struktur von Netzwerkverbindungen hat die ISO (International Standardization Organization) ein Sieben-Schichten-Modell, das OSI-Modell (Open Systems Interconnection) entworfen, das alle Aspekte der Netzwerkkommunikation abdeckt: Physikalische Schicht: Bitübertragung Übertragungsschicht: Sicherung gegen Datenausfälle (z.B. EtherNet) auf Hardware-Ebene Vermittlungs-/Netzwerkschicht: z.B. Internet-Protocol (IP) KAPITEL 7. NETZWERKKOMMUNIKATION 102 Transportschicht: TCP (Transmission Control Protocol), UDP (User Datagram Protocol) Kommunikationsschicht: RPC (Remote Procedure Calls) Darstellungsschicht: Rechnerunabhängige Datenrepräsentation, z.B. XDR (eXternal Data Representation) Anwendungsschicht: NFS (Network File System), YP (Yellow Pages), LDB (Lexicon DataBase) Während die physikalische, die Übertragungs- und die Netzwerkschicht vornehmlich Hardware-Aspekten unterworfen sind, handelt es sich bei den höheren Schichten fast ausschließlich um Software-Protokollschichten. Dabei decken die Protokolle verschiedene Aspekte der Kommunikation zwischen Rechnern ab. Allen gemeinsam ist die Aufgabe, die Datenübertragung so transparent und rechnerunabhängig, vor allem aber so sicher wie nur irgend möglich zu gestalten. Protokolle wie TCP stecken sehr hohen Aufwand in die Kodierung der abgehenden und Dekodierung der ankommenden Daten, um Datenverluste durch die Übertragung zu erkennen und durch geeignete Verfahren zu korrigieren. Die Transparenz wird dadurch gewährleistet, daß jedes Protokoll für sich gekapselt ist, und unabhängig von der jeweiligen Implementation, nach außen in seiner Funktionalität für die höheren Schichten gleich aussieht. 7.2.2 Remote Procedure Calls Für die vorliegende Arbeit galt es, die Netzwerkkommunikation in einer möglichst hohen Schicht anzusiedeln. Die Vorteile der Arbeit in den höheren Schichten besteht in der nach oben hin zunehmenden Transparenz der Kommunikation für den Benutzer (i.e. den Programmierer). Außerdem erfüllen nur die oberen Schichten die Forderung nach Hardware-Unabhängigkeit der Anwendungen. Als Kommunikationsmodell werden RPCs (Remote Procedure Calls) verwendet, die im OSI-Modell in der Kommunikationsschicht anzusiedeln sind. Als darunterliegendes Transportprotokoll wird aufgrund von Überlegungen zur Sicherheit des Transports TCP benutzt. TCP hat gegenüber UDP den Vorteil, keine Beschränkung in der Größe der zu verschickenden Paketet zu haben. Es handelt sich bei RPCs um entfernte Funktionsaufrufe. Ähnlich wie in einem Programm eine programminterne oder Bibliotheksfunktion aufgerufen wird, werden auch RPCs mit Argumenten und Rückgabewerten aufgerufen. KAPITEL 7. NETZWERKKOMMUNIKATION 103 Der Unterschied zu “normalen” Funktionsaufrufen besteht darin, daß das aufrufende Programm und die abarbeitende Funktion in zwei getrennten, entfernten Prozessen liegen, und die Kommunikation zwischen den beiden Prozessen durch ein Transportprotokoll über das Netz durchgeführt wird. In tieferen Schichten der Netzwerk-Kommunikation werden von den beteiligten Rechnern Ports (Zugänge) zur Verfügung gestellt, die wiederum durch den PortMapper eines Netzwerks verwaltet werden. Die Ports werden über die Sockets des Netzwerks realisiert. Sockets sind eine Programmierschnittstelle für die Interprozeßkommunikation. Die Tatsache, daß es sich bei RPCs um Funktionsaufrufe handelt, impliziert, daß die Aktivitäten vom Client ausgehen. Dieser initiert den Funktionsaufruf (einschließlich Parameterübergabe) und wartet dann, bis der Server auf den Funktionsaufruf reagiert hat, indem er die Ergebnisse der Funktion zum Client zurückgibt. Der Vorgang eines RPCs wird als Übersicht in Abbildung3 7.3 dargestellt. Mit Ausnahme der broadcast-Aufrufe wartet der Client immer auf eine Antwort des Servers, bzw. wenn diese nicht innerhalb eines festgelegten Zeitraums (timeout) erfolgt, bricht er das Warten mit einer Fehlermeldung ab. RPCs stellen somit keine ständige, stehende Verbindung her, sondern eine, die nach den Bedürfnissen des Clients aufgebaut und nach dem Abarbeiten der Funktion im Server sofort wieder abgebaut wird. Zwar müssen die verwendeten Sockets explizit wieder an das System zurückgegeben werden, jedoch besteht zwischen den Kontaktversuchen des Clients keine Verbindung zum Server, so daß die Belastung des Netzwerkes minimal bleibt. Daraus folgt, daß im Falle eines Fehlers im Server, der den Server-Prozess vorzeitig beendet, der Server keine Möglichkeit hat, die ihn aufrufenden Clients über die Art des Fehlers noch über dessen Auftreten an sich zu informieren. Die Clients können höchstens beim nächsten Aufruf feststellen, daß ihr Server nicht mehr läuft. Sollen die Clients wie im Falle der LDB ständig mit dem Server in Verbindung stehen, muß das Verhalten simuliert werden, daß der Server die Clients verständigen kann. Darauf wird weiter unten noch eingegangen werden. 3 Die Abbildung wurde übernommen aus [26], S. 155 KAPITEL 7. NETZWERKKOMMUNIKATION Rechner A Client-Prozess Rechner B Server-Prozess Client läuft ab Server wartet RPC-AufrufNachricht Client wartet 104 Netzwerk Server läuft an ProzedurAufruf Server läuft ab ProzedurRückkehr RPC-RückgabeNachricht Aufruf beendet Abbildung 7.3: Typischer Ablauf eines Remote Procedure Calls Eine weitere wichtige Einschränkung bei der Verwendung von RPCs ist die Tatsache, daß ein Client keine Möglichkeit hat, herauszufinden, auf welchem Rechner im Netz der Server läuft, der die von ihm gewünschte Funktion zur Verfügung stellt. Der Server-Rechner muß also dem Client immer bekannt sein, d.h. durch Konfigurationsdateien, die sich Client und Server teilen bzw. durch feste Kodierung im Client-Programm. In den unterschiedlichen Rechnersystemen, die in einem Netzwerk aufeinandertreffen können, werden Daten, z.B. Zahlen oder Speicheradressen, durch eine unterschiedliche Reihenfolge von Bytes repräsentiert werden. Man unterscheidet die Repräsentation von Adressen nach zwei Arten: KAPITEL 7. NETZWERKKOMMUNIKATION 105 Little Endian: Bei einer 16-Bit- (= 2-Byte-) Darstellung wird zuerst das höherwertige Byte und dann das niederwertige Byte dargestellt. Diese Repräsentation findet sich z.B. bei Rechnern mit Prozessoren der Firmen Intel (Reihe 80x86) oder DEC VAX. Big Endian: Hier ist die Reihenfolge umgekehrt wie beim Little Endian. Diese Repräsentation findet sich z.B. bei Rechnern mit Prozessoren der Firmen Motorola (Reihe 680x0) und IBM (Reihe 370). Die Forderung nach Verbindungen zwischen Rechnern, die verschiedene Zahlenrepräsentationen verwenden, machte die Entwicklung eines Umsetzungsmechanismus notwendig. Dieser ist in Form des XDRs (eXternal Data Representation) realisiert. XDR-Routinen wandeln Daten des Clients (i.e. die Funktionsargumente) in ein Versandformat um, welches beim Server wieder in dessen eigenes internes Datenformat umgesetzt wird. In einem bestehenden RPC-fähigen System gehören die XDR-Routinen für die Basistypen dieses Systems (integer, long, float) zur Grundausstattung. Will ein Programmierer eigene Datentypen in RPCs verwenden, kann er sich der XDR-Beschreibungssprache4 bedienen. Die XDR-Beschreibungssprache ist der Programmiersprache C sehr ähnlich. In einigen Punkten weist sie Konstrukte auf, die von C abweichen, aber speziell für XDR nötig sind. RPCs wurden ursprünglich von den Firmen SUN Microsystems und HewlettPackard spezifiziert, implementiert und eingeführt. Mittlerweile sind RPCs auf vielen netzwerkbenutzenden Systemen verfügbar (so z.B. auch Microsoft Windows NT, IBM OS/2 Warp). Die Erfinder wollten, daß RPCs ein möglichst einfach zu benutzendes Instrument für Netzwerkprogrammierer sein sollten. Im Interesse einfacher Programmierung entwickelten sie einen C-Quelltext-Generator, rpcgen5 , der ebenfalls wie die Basistypen-Deklarationen zum jeweiligen System dazugehört. rpcgen compiliert aus einer Datei, die in der XDR-Beschreibungssprache vorliegt, mehrere Quelltext-Module in der Programmiersprache C. Diese Module beinhalten die XDR-Routinen, um die in der XDR-Beschreibungsdatei spezifizerten “Versand”Repräsentationen in ein Transportformat umzuwandeln; die Client-Routinen, um die Anbindung an einen Server herzustellen; ein Modul, das die Abarbeitung ein4 [17], 5 Eine S. 5-1ff ausführliche Beschreibung des rpcgen findet sich in [17], S. 4-1ff KAPITEL 7. NETZWERKKOMMUNIKATION 106 gehender Anfragen der Clients im Server übernimmt. Dazu kommen noch diverse Routinen zur Fehlerbehandlung. Die Aufgabe des Programmierers, der RPCs benutzen will, ist es, ein Modul mit den eigentlichen “Arbeitsfunktionen” zur Verfügung zu stellen. Durch dieses Vorgehen wird der Programmierer von den Aspekten der NetzwerkKommunikation größtenteils entlastet. Er muß sich vor allem mit der Repräsentation seiner Daten beim Funktionsaufruf und im Server kümmern. rpcgen ist in seiner Arbeitsweise verhältnismäßig primitiv. Bei der Abarbeitung der XDR-Beschreibungsdatei wird zwar der C- bzw. C++-Präprozessor genutzt, auch kann Quelltext verbatim in die zu erzeugenden Header-Dateien und QuelltextModule übernommen werden. Doch will man in die Funktionen, die die RPCVerbindung aufbauen, eigenen Quelltext integrieren, so kann von rpcgen nur ein Mustermodul erzeugt werden. Vor allem weitergehende RPC-Projekte lassen sich nur “per Hand” realisieren, z.B. die Verwendung von Broadcast-Aufrufen. Nichtsdestoweniger enthebt rpcgen den Programmierer des ermüdenden Erstellens der Basismodule für Client und Server, wenn nur eine Standardlösung gebraucht wird. 7.3 Netzwerkkommunikation in der Lexikondatenbank Zuerst sollen noch einmal die Anforderungen für die Netzwerkschnittstelle der LDB aufgelistet werden: Aufbauen und Abbrechen der Client-Server-Verbindung Übertragung von Lexikoneinträgen vom Client zum Server Übertragung von Lexikoneinträgen vom Server zum Client Ausführen von Operationen, die die Gesamtdatenbank, einzelne Einträge im Lexikon oder die Arbeit des Servers betreffen. Statusinformation des Servers an den Client, Fehlerbehandlung im Serverund Client-Programm Identifizierung der Client-Benutzer und Zuteilen der entsprechenden Rechte Die Zugangsregelung ist ein zentrales Anliegen bei der Implementierung der LDB. Damit der Zugang effektiv gestaltet werden kann, ist es sinnvoll, alle ClientBenutzer der LDB durch eine Funktion zu führen, in der ihre Berechtigung und KAPITEL 7. NETZWERKKOMMUNIKATION 107 die mit ihrer Benutzer-Gruppe zusammenhängenden Rechte in der Arbeit mit der LDB festgestellt werden. Unberechtigte Benutzer sollen abgewiesen werden. 7.3.1 Remote Procedure Calls in der LDB Für die Programmierung von RPCs ist es vorgesehen, für jede Funktionalität des Servers eine Funktion zur Verfügung zu stellen. Dieses Vorgehen weist jedoch für den Fall der LDB einige gravierende Nachteile auf. Die Benutzer-Identifikation müßte in jeder einzelnen Funktion der LDB vorgenommen werden, die über RPCs angesprochen wird. Dies ist mit Hinsicht auf übersichtliches Programmieren nicht annehmbar. Eine Änderung des automatisch generierten Server-Moduls, um die Benutzeridentifikation einzubinden, verbietet sich, da dieser Quelltext jedesmal neu generiert wird, wenn die XDRBeschreibungsdatei verändert wird. Änderungen im Server-Modul lassen sich nur über die Hauptroutine des Serverprogramms einbauen. Da dieses Modul aber nur einmal, beim Starten des Servers, durchlaufen wird, steht es für die Durchführung der Benutzeridentifikation nicht zur Verfügung. Diese Einschränkungen und weitere Gründe6 führten dazu, daß in der LDB eine zentrale Funktion vorhanden ist, in der grundsätzlich zu Beginn einer jeden Anfrage von Benutzern die Benutzeridentifikation vorgenommen wird. Dann wird mithilfe einer Kennziffer der vom Client gewünschte Server-Dienst ausgewählt und die Rechtmäßigkeit dieses Wunsches anhand der Rechte des Benutzers festgestellt. Erst dann, wenn die Berechtigung des Benutzers feststeht, kann der entsprechende Dienst ausgeführt werden. Die Kennziffern der verschiedenen Server-Dienste werden in der XDRBeschreibungsdatei festgelegt. Auf dieselbe Art und Weise wird im Client-Programm vorgegangen. Vor dem RPC werden die für den Server bestimmten Daten zusammengestellt. In Client und Server wird dazu ein Aufrufverbund (engl. call record) verwendet, der als einziges Argument beim RPC übergeben wird. Der Aufrufverbund bietet Platz für zwei Zeichenketten, zwei lange Zahlen (LONG INT) und zwei kurze Zahlen (INT). Diese Felder sind für die Anwendung in der LDB ausreichend. Vor dem RPC wird der Verbund vom Client mit den entsprechenden Daten gefüllt, von denen eines die 6 Während der Vorarbeiten zur LDB ließ sich feststellen, daß die in der Computerlinguistik Erlangen installierte Version des rpcgen scheinbar nicht fähig ist, Funktionsaufrufe mit weniger bzw. mehr als einem Argument zu akzeptieren. Dies entspricht offensichtlich nicht der RPC-Spezifikation, nach der beliebig viele Argumente zulässig sind. KAPITEL 7. NETZWERKKOMMUNIKATION 108 Kennziffer des Serverdienstes ist. Beim Eintreffen des Aufrufs in der zentralen Server-Funktion wird zuerst der Verbund ausgepackt. Dann erfolgen die der Kennziffer entsprechenden Server-Operationen. Durch die Verwendung dieses Verbunds wird neben der Benutzeridentifikation auch die Datenübermittlung auf eine Stelle konzentriert. So lassen sich Erweiterungen z.B. im Befehlssatz des Servers und des Clients leichter vornehmen. Für den Rückversand der Ergebnisse vom Server zum Client wird ebenfalls wieder ein solcher Verbund verwendet, allerdings wird dessen Definition grundlegend durch rpcgen bestimmt. Die Grundfelder dieses Verbundes sind festgelegt. Der Programmierer kann jedoch einige Felder hinzufügen. Kurz vor dem Verlassen der zentralen Server-Funktion wird der Rückgabe-Verbund gefüllt und mit dem Verlassen dieser Funktion an den Client als Antwort auf dessen Anfrage zurückgeschickt. Bei der Ankunft im Client-Programm wird der Rückgabe-Verbund in einer speziellen Funktion des Clients überprüft. Die Überprüfung ist deswegen notwendig, weil mit dem Verbund unter Umständen dem Client Fehler, die im Server aufgetreten sind, mitgeteilt werden. Diese sind vor einer Auswertung der Rückgabewerte an den Benutzer abzufangen. Die Benutzer-Identifikation erfolgt in der LDB UNIX-konform, d.h. die Rechte des Benutzers in der LDB leiten sich aus seinen Benutzer- und Gruppenrechten im UNIX-System des Benutzers ab. Die einzelnen Benutzergruppen werden in Abschnitt 5.6 erklärt. Die RPCs transportieren neben den Argumenten des Funktionsaufrufes u.a. weitere Informationen über den Client zum Server, z.B. die Rechte des Client-Benutzers in dessen UNIX-System. Da sich im Fall der LDB der Server-Rechner im gleichen Cluster bzw. im Nebencluster befindet wie der Client-Rechner, und sich Client und Server das gleiche Dateisystem teilen, stimmen die Rechteregelungen zwischen Client und Server überein, so daß an dieser Stelle keine weiterführenden Mechanismen vorgesehen wurden. 7.3.2 Simulation einer Duplex-Verbindung Um die oben erwähnte Beschränkung, daß der Server von sich aus keine Nachrichten an die Clients verschicken kann, zu umgehen, wurde ein PING-Aufruf implementiert. Dieser Funktionsaufruf stellt eine Anfrage an den Server dar, ob bei diesem noch alles in Ordnung ist. Der Server kann dann entsprechend antworten. Wird dieses PING auf der Client-Seite so implementiert, daß der Server periodisch angepingt wird, dann kann der Server davon ausgehen, daß ihn jeder Client in KAPITEL 7. NETZWERKKOMMUNIKATION 109 maximal dieser Zeitspanne anrufen wird, und daß er nach dieser Zeitspanne ohne Probleme herunterfahren kann, weil dann alle Clients verständigt sind. Das Intervall, in dem ein Client dem Server ein PING schickt, ist geeignet zu wählen, so daß die Netzkommunikation nicht durch eine Flut an PINGs zum Erliegen kommt. Zum jetzigen Zeitpunkt ist das PING als eine leere Funktion implementiert, die nur einen OK-Wert zurückgibt. Der Client kann das PING-Kommando nutzen, um nach einem Timeout der RPC-Verbindung die Wiederbereitstellung der Serverdienste zu erfassen (mehrfaches Timeout). Ein Timeout bedeutet nämlich vorerst keinen Fehlerzustand im Netzwerk oder beim Server, sondern nur, daß der Server beschäftigt ist und auf derzeitige Anfragen nicht eingehen kann. Dies ist im Gegensatz zu einer Unterbrechung der RPC-Verbindung zu sehen, bei der eindeutig eine Fehlersituation vorliegt. Diese äußert sich aus der Sicht des Clients durch einen Protokollfehler. Je nach Art der Fehlerbedingung, die dem Client durch das RPC zur Verfügung gestellt wird, kann der Client z.B. auf einen möglichen (fatalen) Server-Shutdown reagieren. Eine Alternative zu dem PING-Mechanismus wäre denkbar, indem zwei weitere Module mit rpcgen generiert werden. Diese stellen eine zweite Verbindung zwischen Client und Server her, aber in der umgekehrten Richtung der ersten. Der ursprüngliche Client würde dann Server (= Empfänger) für den ursprünglichen Server, der seinerseits dann Client des ursprünglichen Clients wäre. Diese Art einer Duplex-Verbindung müßte der Server dann zu jedem anderen der gerade angebunden Clients aufbauen. Das Zusammenbinden der verschiedenen Server- und Client-Module ist nur über ausführliche Protokolle denkbar, die mit Hilfe von Interprozeßkommunikation (IPC) zu implementieren wären. Die beschriebene Alternative würde weitere Probleme aufwerfen. Das Client-Programm müßte gleichzeitig Benutzeranfragen erwarten und verschicken, aber auch immer auf den Server, d.h. seinen Client, lauschen. Eine solche doppelte Verbindung könnte das Netzwerk stark belasten. Aber auch im Server ist diese Alternative schwer einzubinden. Würde der Server alle seine Clients via RPC anrufen, einer von diesen aber aus irgendwelchen Gründen nicht antworten, so bliebe der Server an dieser Stelle mit der Programmabarbeitung stehen. Er könnte dann nicht mehr die Anfragen der Clients annehmen. Gleichzeitig könnte aber der gerade nicht vom Server aus erreichbare Client beim Server eine Anfrage starten. Das gegenseitige Warten auf Antwort würde zu einer Dead-Lock-Situation führen, die nur durch Abbrechen der Verbindung eines der beteiligten Module zu beseitigen würde. Dies zu erkennen und aufzuheben sind aber beide Prozesse nicht in der Lage. KAPITEL 7. NETZWERKKOMMUNIKATION 110 Wie man sehen kann, erfordert die Alternativ-Lösung zur PING-Funktion einen hohen Implementationsaufwand sowohl auf der Server- als auch auf der ClientSeite. Das Entwerfen und Implementieren z.B. der Mechanismen zur Dead-LockVermeidung sprengen jedoch den Rahmen dieser Arbeit, zumal der erforderliche Aufwand im Vergleich zum erwartbaren Nutzen sehr hoch ist. Kapitel 8 Beschreibung der erstellten Programme 8.1 Konfigurationsdateien Zur Konfiguration eines Programms gibt es mehrere Möglichkeiten. Die Konfiguration kann erfolgen über 1. in den Quelltext eingebaute Konstanten; 2. Umgebungsvariablen; 3. die Kommandzeile mit Hilfe von Optionen und Schaltern oder 4. Konfigurationsdateien. In der LDB werden die beiden letzten Möglichkeiten verwendet. Die erste Lösung ist nur wenig praktikabel, da durch solche Veränderungen ein Neucompilieren der LDB zwingend notwendig ist. Außerdem sollen nur wenige Benutzer, im allgemeinen nur der Systemadministrator, den Zugang zum Quelltext der LDB haben, um folgenschwere, destruktive Eingriffe in den Programmablauf zu verhindern. Die Veränderungen im Quelltext fordern im übrigen ein gutes Verständnis für die internen Strukturen der LDB seitens des Benutzers. Diese Voraussetzung ist sicher nur bei wenigen Benutzern gegeben. Die Verwendung von Umgebungsvariablen bedeutet für den Datenbankbenutzer meist, daß er Veränderungen in seinen Startdateien (z.B. das login-script) o.ä. vor111 KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 112 nehmen muß, um die Umgebungsvariablen beim Einloggen mit den entsprechenden Werten zu belegen. Auch dieses Vorgehen ist im Sinne eines unkomplizierten Umgangs mit der LDB nicht wünschenswert. Die dritte Möglichkeit bietet sich für Optionen an, die einmalig beim Start des jeweiligen Programms übergeben werden sollen, aber nicht unbedingt bei jedem Neustart des Programms. Dazu gehören Schalter, die das jeweilige Programm veranlassen, z.B. einen Hilfetext über alle möglichen Startoptionen auszugeben, ohne das Programm richtig zu starten. Am wichtigsten für die LDB ist die Konfiguration über Konfigurationsdateien (engl. profile). In diesen können Startoptionen dauerhaft festgelegt werden, ohne daß der Benutzer diese jedesmal erneut eingeben muß. Zur Implementation von Konfigurationsdateien gibt es verschiedene Beispiele, wie z.B. die .kshrc zur Konfiguration der Korn-Shell, .emacs zur Konfiguration des Emacs-Editors oder die Ressourcendateien des X-Window-Systems. Konfigurationsdateien werden im allgemeinen entweder vom jeweiligen Programm selbst anhand der Änderungen modifiziert, die ein Benutzer während der Programmbenutzung vorgenommen hat, oder vom Benutzer, der zu diesem Zweck die Konfigurationsdatei mit einem Editor-Programm bearbeitet. Sofern das jeweilige Programm seine Eintragungen in die Konfigurationsdatei nicht im Klartext1 und strukturiert vornimmt, ist die zweite Lösung, das Eintragen der Optionen durch den Benutzer die flexiblere Lösung. In der LDB werden durch den Benutzer edierbare Konfigurationsdateien verwendet. Ihr Format lehnt sich dabei an das der MS-Windows-INI-Dateien2 und das Format der X-Window-Ressourcen-Dateien3 an. Eine Konfigurationsdatei besteht aus Eintragszeilen. Jeder Eintrag besteht aus einem Schlüsselwort und einem Wert. Werte werden durch ein Zeilenende abgeschlossen. Mehrere Einträge werden zu Abschnitten zusammengefaßt. Ein Abschnitt wird markiert, am Beginn durch den Abschnittsnamen, am Ende durch den Abschnittsnamen des folgenden Abschnitts oder das Dateiende. 1 Klartext meint hier eine durch andere Programme lesbare und evtl. bearbeitbare Repräsentation wie z.B. ASCII-Text. 2 [19], S. 178f 3 [5], S. 69f KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 113 Die Übersicht in Tabelle 8.1 zeigt die Definition des Formats der in der LDB verwendeten Konfigurationsdateien in EBNF4-ähnlicher Notation. KONFIGURATIONSDATEI ::= fABSCHNITTg DATEIENDE ABSCHNITT ::= ABSCHNITTSNAME ::= “[” ABSCHNITTSNAME “]” fLEERZEICHENg EOL fEINTRÄGEg ZEICHENKETTE EINTRÄGE EINTRAG ::= ::= SCHLÜSSELWORT WERT ::= ::= EINTRAG fLEERZEICHENg EOL fLEERZEICHENg SCHLÜSSELWORT fLEERZEICHENg WERT ZEICHENKETTE [ZEICHENKETTE] ZEICHENKETTE ZEICHEN EOL LEERZEICHEN DATEIENDE ::= ::= ::= ::= ::= ZEICHEN fZEICHENg beliebiges Zeichen außer “[”, “]” und EOL Zeilenendemarkierung Leerzeichen Dateiendemarkierung Tabelle 8.1: EBNF-Darstellung des Formats der Konfigurationsdateien Im folgenden Beispiel sieht man die LDB-Server-Konfigurationsdatei: [admin] root-group: db-adm [files] server-dir: server-log-dir: /users/projects/ldb/svc /users/projects/ldb/svc/log Zur Zeit ist nur eine Funktion zum Zugriff auf die Konfigurationsdateien implementiert. Sie extrahiert aus einer angegebenen Konfigurationsdatei den Wert (eine Zeichenkette) zu einem Eintrag eines Abschnitts. Dies genügt jedoch vollauf für die Belange der LDB. 4 ebd., S. 69 unten “:” KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 114 Da die Konfigurationsdateien im ASCII-Format vorliegen, können sie durch den Benutzer mit jedem Editor-Programm geändert werden. In der LDB werden drei Konfigurationsdateien verwendet: die Server-Konfigurationsdatei die Client-Konfigurationsdatei die Datenbank-Konfigurationsdatei Auf die Abschnitte und Einträge dieser Dateien wird in den folgenden Abschnitten dieses Kapitels im Rahmen der Beschreibung der einzelnen Programme eingegangen. 8.2 Server- und Clientprogramme 8.2.1 Das Serverprogramm ldb Das Serverprogramm der LDB wird in eine Datei namens ldb compiliert. Um das Serverprogramm zu erzeugen, werden alle Quelltextdateien mit dem Präfix ldb und db compiliert und zusammengebunden. Zum Ausführen des Programms wird eine Server-Konfigurationsdatei (engl. server profile) benötigt. Über diese lassen sich folgende Rahmenbedingungen für den Betrieb des Servers einstellen: Im Abschnitt “[admin]” wird die Benutzergruppe (als Zeichenkette) der Root-Benutzer festgelegt, die uneingeschränkten Zugang zu den Serverdiensten hat (Eintrag “root-group”). Im Abschnitt “[files]” werden die Pfadnamen der Verzeichnisse in denen das Serverprogramm liegt (Eintrag “server-dir”) und in die das Serverprogramm seine Protokolldateien legen soll (Eintrag “server-log-dir”), vermerkt. Die Konfigurationsdatei wird einmalig beim Starten des Serverprogramms ausgelesen. Ein Benutzer, der das Serverprogramm starten will, muß Mitglied in der Benutzergruppe sein (und auch unter dieser zum Zeitpunkt des Aufrufs arbeiten), die in der Konfigurationsdatei als Gruppe der Root-Benutzer eingetragen ist. Andernfalls startet der Server nicht und bricht mit einer entsprechenden Meldung ab. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 115 Das Serverprogramm ldb kann mit den Parametern -v, -p und -s in der UNIXKommandozeile gestartet werden: Die Option -v veranlaßt das Serverprogramm beim Starten ausführlichere Informationen über die gerade vorgenommenen Aktionen auf dem Bildschirm auszugeben. Ein Aufrufen des Programms ohne die Option -s sorgt dafür, daß alle Ausgaben, die sonst durch das Serverprogramm auf dem Bildschirm ausgegeben würden, in eine Datei umgelenkt werden. Diese Datei legt der Server in dem Verzeichnis an, das im Abschnitt “[files]”, Eintrag “server-log-dir” als Protokoll-verzeichnis angeführt wird. Ist kein solcher Eintrag vorhanden, verwendet der Server als Voreinstellung das aktuelle Verzeichnis, von dem aus das Serverprogramm gestartet wurde, als Protokollverzeichnis. Der Name der Protokolldatei wird am Bildschirm angezeigt, bevor die Ausgaben in die Protokolldatei umgelenkt werden. Wird -s angegeben, erfolgen alle Ausgaben während der Serverlaufzeit auf die Standard-Fehlerausgabe des Programms. Zusammen mit der Option -p ist (getrennt durch mindestens ein Leerzeichen) der Name einer Datei bzw. eines Pfadnamens anzugeben. Diese Datei wird das Serverprogramm als Konfigurationsdatei anstelle der Voreinstellung verwenden. Der Standardname für die Konfigurationsdatei lautet .ldbsvcrc und ist im Quelltext des Serverprogramms festgelegt. Der Server sucht nach dieser Datei, wenn keine andere explizit in der Kommandozeile angegeben wurde. Das Serverprogramm kann im Hintergrund gestartet werden, wenn die Option -s nicht angegeben wird. Dies ist die Voreinstellung. Nach dem Start des Programms begibt sich dieses nach Einlesen und Auswerten der Konfigurationdatei in die RPC-Warteschleife. Es verharrt dort so lange, bis entweder ein RPC auszuführen ist, bzw. bis ein Shutdown-Kommando das Serverprogramm beendet. Bis das erste RPC-Kommando an das Serverprogramm erfolgt, läuft dieser mit minimalem Ressourcen-Aufwand. Erst dann werden benötigte Datenstrukturen initialisiert. Beim Starten des Serverprogramms werden Signale, die zur InterprozeßKommunikation dienen, so umgeleitet, daß das Serverprogramm bei den wichtigsten Signalen (SIGTERM, SIGQUIT, SIGHUP, SIGINT) zuerst einen ordnungsgemäßen Shutdown macht, bevor das Serverprogramm beendet wird. Hierin ist KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 116 eine Vorsichtsmaßnahme für den Fall zu sehen, daß der Benutzer, der das Serverprogramm gestartet hat, z.B. aus Versehen in der Eingabezeile Control-C drückt. Dies löst das Verschicken eines SIGTERM an den jeweiligen Prozeß (in diesem Fall das LDB-Serverprogramm) aus. 8.2.2 Die Testshell ldbsh Nach der Beschreibung der Serverseite der LDB sollen nun die Programme auf der Client-Seite beschrieben werden. Ursprünglich war die Shell5 eine kleine Eingaberoutine, um einbuchstabige Kommandos an die Urdatenbankkomponente zu übergeben. Mit der Fortentwicklung des Projekts, v.a. aber durch die Implementation der LDB mit RPCs wurde die Shell zu einem eigenständigen Clientprogramm. Sie unterstützt mittlerweile 35 Befehle, die sowohl in einer Lang- als auch in einer Kurzform eingegeben werden können. Die Shell nimmt Klartextbefehle und die erwarteten Argumente dazu aus einer Eingabezeile entgegen, die danach ausgewertet werden. Dabei überprüft die Shell, ob die Anzahl der geforderten Befehlsargumente stimmt, und ob bestimmte, festgelegte Argument vom Benutzer in der richtigen Form angegeben wurden. Ist dies nicht der Fall, reagiert die Shell mit einer Fehlermeldung. Danach kann der Benutzer erneut versuchen, das Kommando in der richtigen Form einzugeben. Nachdem die Shell die Argument des jeweiligen Kommandos überprüft hat, setzt sie den entsprechenden RPC an der Server ab. Dann wartet die Shell, bis der RPC vom Server beantwortet wird. Erfolgt die Antwort nicht in der vorgesehen Zeit (engl. timeout), versucht die Shell bis zu fünf Mal, den Kontakt zum Server wiederherzustellen. Gelingt dies nicht in der fünffachen Timeout-Periode, bricht die Shell ihre Serveranfragen mit einer entsprechenden Meldung ab. Der Regelfall ist jedoch, daß der Server in sehr kurzer Zeit eine Antwort zurückgibt. Die Shell gibt dann die Ergebnisse des RPC in geeigneter Form auf dem Bildschirm aus. Dann steht die Shell an der Eingabeaufforderung für erneute Benutzereingaben zur Verfügung. Ebenso wie das Serverprogramm ist auch das Verhalten der Shell beim Starten über 5 “The term ‘shell’ gets its name from the UNIX system [whose] kernel is surrounded by programs [...] that perform specific tasks. A program that provides access to these utilities by the user is called a shell”[4], S. 3 KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 117 eine Konfigurationsdatei und Kommandozeilenparameter einstellbar. Der voreingestellte Name dieser Datei ist .ldbclntrc im aktuellen Verzeichnis. Die Konfigurationsdatei kann folgende Abschnitte und Einträge enthalten: Im Abschnitt “[host]” kann mit dem Eintrag “server” eine Voreinstellung für den Rechner eingegeben werden, mit dem die Shell beim Starten die Verbindung herstellen soll. über den Eintrag “timeout” im Abschnitt “[client]” kann die Zeit festgelegt werden, in der die Shell auf eine Antwort auf einen RPC erwartet. Auch für die Shell gibt es einen Abschnitt “[files]”, in dem ein Verzeichnispfad angegeben werden kann. In dieses Verzeichnis legt das Serverprogramm Protokoll-Dateien für den Benutzer der Shell. Diese Dateien werden erzeugt, wenn der Benutzer den Server anweist, neue Einträge aus einer Datei ins Lexikon einzulesen. Wird hier keine Eintragung gemacht, versucht die Shell als Voreinstellung, ein Verzeichnis .ldb im HOME-Verzeichnis des Benutzers einzurichten. Schlägt dies fehl, weicht die Shell auf das StandardTMP-Verzeichnis des jeweiligen Rechners aus. Sollten während der Nutzung des Servers oder des Betriebs der Shell Fehler auftreten, so meldet die Shell diese unter Angabe einer Fehlernummer. Wie schon im Abschnitt über die Fehlerbehandlung erklärt, verwenden Client und Server dieselben Fehlernummern. Dies trägt wesentlich zur Einfachheit der Fehlerverarbeitung und -anzeige bei. Neben Server-Fehlern können Fehler auftreten, die nur die Shell betreffen. Solche Fehler sind z.B. die Überschreitung der maximalen Timeout-Dauer, unbekannte ldbsh-Befehle, fehlende oder falsche Befehlsargumente, etc. Neben den ServerFehlernummern, die im Zahlenbereich zwischen 0 und 200 liegen können, gibt es die Fehlernummern der Client-Programme, die im Zahlenbereich über 300 liegen. Neben der Fehlernummer wird gleichzeitig eine Klartextmitteilung zu dem betreffenden Fehler ausgegeben. 8.2.2.1 D IE B EFEHLE DER S HELL Die Befehle der Shell lassen sich in mehrere Gruppen gliedern. Es sind dies Befehle, 1. die die Shell betreffen, KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 118 2. um den Server zu manipulieren, 3. um Dienste des Servers zu erhalten, 4. um den Betriebszustand des Servers zu kontrollieren. Ihrer Natur gemäß unterscheiden sich die Befehle hinsichtlich der Berechtigung des Benutzers im Zugriff auf den Server. Die Shell überprüft die Berechtigung des Benutzers jedoch nicht. Dies geschieht ausschließlich im und durch den Server. Jeder Befehl besteht aus einem Befehlswort und keinem, einem oder mehreren Argumenten, die von einander durch mindestens ein Leerzeichen getrennt sind. Die Shell überprüft, ob die Mindestanzahl an Argumenten eingegeben wurde. Überzählige Argumente werden mit dem letzten Argument konkateniert. Dieses Vorgehen ist notwendig, da für den Fall, daß eines der Argumente ein Lexikoneintrag ist, dieser am Stück in die Datenbank übertragen werden soll. Da Lexikoneinträge unter anderem auch Leerzeichen enthalten dürfen, können auf die beschriebene Weise die Teile des Lexikonseintrag zusammengehalten werden, die sonst als mehrere Eingabezeilenargumente interpretiert würden. Alternativ zum Befehlswort kann auch eine einbuchstabige Abkürzung (engl. shortcut) eingegeben werden. Die Liste aller von der Shell unterstützten Befehle findet sich in Anhang A. 8.2.3 Die Client-Schnittstelle ldbcall In enger Verbindung mit der vorgestellten Shell ldbsh steht das Programm ldbcall. ldbcall ist die Kommandozeilen-Version der Shell. Es steht nicht wie bei der Shell die Eingabeaufforderung der Testshell zur Verfügung, an der die Befehle der LDB eingegeben werden können. Mit ldbcall kann bei jedem Aufruf nur ein Befehl an die LDB abgesetzt werden. Die Entwicklung dieses Programms erwies sich als notwendig, um Programme, die keinen Code zur direkten Ansteuerung der LDB enthalten, mit der LDB verbinden zu können. Beispiel eines solchen Programmes ist die weiter unten vorgestellte grafische Benutzeroberfläche xLDB. Natürlich ergeben sich aus der Tatsache, daß die Verbindung zum Server jedesmal vollständig neu auf- bzw. auch wieder abgebaut wird, Veränderungen in der Funktionalität von ldbcall gegenüber der ldbsh. Diese Unterschiede sind fast ausschließlich in der Behandlung der Kommandozeile beim Start des Programms anzutreffen. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 119 Deshalb konnten die wichtigsten Teile beider Programme, ldbcall und ldbsh, gemeinsam entwickelt werden. Diese gemeinsamen Teile sind das Initialisieren der Fehlerbehandlung, der LDB-Befehlsbehandlung, das Aufbauen und Abbauen der Client-Server-Verbindung und schließlich das Aufrufen der RPCs und das Empfangen der Serverantwort nebst der Auswertung der Antwort. ldbcall behandelt die Kommandozeile beim Starten anders als ldbsh. Außerdem greift ldbcall z.B. beim Starten nicht auf eine Konfigurationsdatei zu. Im folgenden sollen die Argumente, mit denen ldbcall aufgerufen wird, aufgeführt und erklärt werden. Die minimale Aufrufsyntax sieht folgendermaßen aus: ldbcall -p <pid> -s <server> -c <command> <args> Im Server werden Benutzer u.a. mit der Prozeß-ID ihres Client-Prozesses identifiziert. Wenn dem Serverprogramm immer die aktuelle Prozeß-ID des ldbcallProzesses übergeben würde, würde das Serverprogramm bei jedem erneuten Aufruf ldbcalls eine andere Prozeß-ID für den Benutzerprozeß erhalten, und somit den Benutzer jedesmal als neuen Benutzer eintragen. Deshalb muß der ldbcall aufrufende Prozeß diesem seine Prozeß-ID mitteilen. Dies geschieht durch den Schalter -p, dem die Prozeß-ID folgt. Eine weitere von ldbcall benötigte Information ist der Name des Servers, zu dem eine Verbindung aufgebaut werden soll. Dieser wird ldbcall nach dem Schalter -s übergeben. Mit dem Schalter -c wird die Kommandozeile für den Serveraufruf eingeleitet. Nach -c wird der Befehl für den Serveraufruf angegeben. Die Befehle entsprechen denen der Shell. Dem Befehl folgen die zugehörigen Befehlsargumente. Nach -c dürfen keine weiteren Schalter für ldbcall mehr folgen, da diese sonst als Argumente zum LDB-Befehl aufgefaßt werden würden. Dies waren die notwendigen Argumente für ldbcall. Daneben gibt es noch optionale Schalter, die das Verhalten des ldbcall-Programms verändern. Der Schalter -v veranlaßt ldbcall beim Programmstart mehr Zustands- und Abarbeitungsinformationen auf dem Bildschirm auszugeben. Diese Option sollte beim Aufruf aus anderen Programmen nur zu Debugging-Zwecken benutzt werden. Ein weiterer Schalter ist -t. Mit -t veranlaßt ldbcall die LDB, ihre Ausgaben für die KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 120 Programmiersprache TCL zu formatieren. Zuletzt gibt es noch den Schalter –version, der eine Kurzanleitung zu den Schaltern und Argumenten, die ldbcall erwartet, beim Aufruf ausgibt. ldbcall macht sämtliche Ausgaben auf die Standardausgabe. Fehlermeldungen werden auf die Standardfehlerausgabe ausgegeben. Ebenso wie LDB oder ldbsh, hat auch ldbcall Fehlernummern für auftretende Fehler. Die Fehlernummern von ldbcall stimmen größtenteils mit denen der Shell überein, jedoch hat ldbcall zusätzliche Fehlermeldungen, um z.B. Fehler in der Kommandozeile zu behandeln. 8.2.4 Kompatibilität Die hier beschriebenen Programme wurden in ANSI-C (ANS X.3-159-1989) implementiert. Die eingesetzten UNIX-Systemaufrufe sind POSIX.1 konform. Als Compiler wurde der GNU-C Compiler in der Version 2.6.3 verwendet. Die Programme wurden unter HP-UX Version 9.05 in der Umgebung der Kornshell Version 11/16/88 auf Hewlett-Packard 9000-720 bzw. 9000-735 getestet. 8.3 Die graphische Benutzeroberfläche xLDB Im vorigen wurde schon eine Zugangsmöglichkeit zur LDB beschrieben, die Shell ldbsh. Die Shell ist als eine erweiterte Kommandozeile anzusehen. Die Kommandozeilen-Funktionalität selbst wird durch das ebenfalls schon beschriebene Programm ldbcall bereitgestellt. Dieses Programm wird v.a. für das im folgenden beschriebene Programm xLDB benötigt, das eine grafische Benutzeroberfläche für den Zugriff auf die LDB zur Verfügung stellt. xLDB implementiert die wesentlichen Funktionen eines Lexikonbetrachters (engl. lexicon viewer) und grundlegende Funktionen eines einfachen Lexikoneditorprogramms. 8.3.1 Die Programmiersprache TCL und das TK Toolkit Um hohen Komfort bei einfacher Programmierung zu erreichen, wurde bei xLDB darauf verzichtet, eine Implementierung direkt auf X-Window- oder OSFMotif-Ebene vorzunehmen. Stattdessen erfolgte die Implementierung der GrafikOberfläche in der Script-Sprache TCL. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 121 Die Tool Command Language (TCL) ist eine interpretierte ScriptProgrammiersprache, die eingehend in [23] vorgestellt und beschrieben wird. TCL (“tickel” ausgesprochen) wurde Ende der 80er Jahre geschaffen und konnte so schon von Anfang an auf die Leistungsdaten, vor allem aber auf die Möglichkeiten moderner Rechner Rücksicht nehmen. TCL implementiert einfache Befehle zur Listen-, Zeichenketten- und Zahlenmanipulation. Daneben gibt es TCL-Äquivalente der wichtigsten Betriebssystem-Funktionen (Datei-Behandlung, usw.). Dabei ist es wichtig, nochmals darauf hinzuweisen, daß TCL “nur” interpretiert wird. Im Gegensatz zu Compilersprachen steht bei interpretierten Programmiersprachen wie TCL immer nur TCL-Quelltext, aber keine Objekt- oder Binärdatei am Ende eines Entwicklungsvorgangs. Vorteil dieser Konzeption sind kurze Turnaroundzeiten bei der Programmentwicklung, da die Compilierzeiten zwischen den Testläufen entfallen. Diese Konzeption hat aber auch Nachteile. Zum einen sind Fehler in nicht sehr häufig oder gar nicht gebrauchten Programmteilen nur schwer auffindbar, da sie u.U. nie interpretiert werden. Zum anderen fehlen bei TCL Werkzeuge wie ein Debugger, mit dem Schritt für Schritt kritische Programmstellen abgearbeitet werden könnten. Für weitergehende, zeitkritische Anwendungsfälle besteht in TCL für Programmierer, die der Sprache C mächtig sind, die Möglichkeit, TCL über eine standardisierte und gut dokumentierte Programmierschnittstelle mit eigenen Routinen zu erweitern, die dann zum Sprachumfang des “neuen” TCL-Interpreters dazugehören. TCL kennt nur einen Datentyp, die Zeichenkette. Diese wird je nach aktuellem Gebrauch für interne Zwecke u.U. in Zahlen umgewandelt, so daß mit TCL auch numerische Operationen möglich sind. Im Hinblick auf die Geschwindigkeit bleibt auf jeden Fall zu konstatieren, daß Zeichenkettenoperationen und rekursive Vorgänge in TCL zeitaufwendig sind. Im übrigen aber verhält sich TCL auf einer Workstation nicht sehr zeitkritisch. Das hier implementierte Programm besteht zum größten Teil aus interaktiven Phasen, so daß wohl meist das Programm auf die Aktionen6 des Benutzers wartet denn umgekehrt. Die Programmiersprache TCL selbst kennt noch keine irgendwie gearteten Befehle, um mit der X-Window-Umgebung7 zu interagieren. Möglich wird das erst unter Verwendung des TK-Toolkits, einer TCL-Erweiterung. TK erweitert den Befehlssatz TCLs um Funktionen zur Programmierung graphischer Benutzeroberflächen8 . 6 Im weiteren Verlauf dieses Kapitel wird mit Aktion jede Tätigkeit des Benutzers in xLDB bezeichnet. 7 Einen Überblick über die X-Window-Umgebung findet man in [5], S. 10ff. oder bei [18], S. 2-1ff 8 Der Begriff graphische Benutzeroberfläche wird im folgenden mit GUI abgekürzt. Dies ist die Abkürzung des engl. Begriffs graphical user interface. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 122 TK stellt dem TCL-Programmierer Widgets9 , die denen der OSF-Motif-Umgebung nachempfunden wurden, und Befehle zur Manipulation von Menü- und Fensterumgebungen zur Verfügung. TK ist in der Programmiersprache C implementiert, da TCL nur auf diese Weise Zugriff auf die Elemente und Funktionen der XLib10 bzw. OSF-Motifs erhalten kann. Durch TK werden die meisten Erfordernisse einer vereinfachten Programmierung von ansprechenden GUIs abgedeckt. In LDB wurde zusätzlich zu TCL und TK das Tix Widget Set11 eingesetzt. Es stellt neben einer TCL-Notation, die objekt-orientierten Ansätzen der Programmierung ähnelt, neue, aus TK-Widgets zusammengesetzte Widgets wie z.B. eine Liste mit automatischen Rollbalken zur Verfügung. 8.3.2 Vorteile einer graphischen Benutzeroberfläche Die Verwendung eines GUI12 für ein Programm wie dem Client-Programm der LDB hat mehrere Vorteile. Im Vordergrund steht aus der Sicht des Programmierers der Wunsch, die freien Eingabemöglichkeiten des Benutzers derart einzuschränken, daß fehlerhafte oder zu einem bestimmten Zeitpunkte logisch nicht sinnvolle Eingaben schon strukturell durch die Implementation des Programms verhindert werden. Dieses Vorgehen faßt man unter dem Begriff Benutzerführung zusammen. Im Verlauf der Programmierarbeiten zu xLDB hat es sich gezeigt, daß die meisten Abfragen auf Eingabefehler in xLDB nie gebraucht wurden, da durch das GUI Eingaben, die zu Fehlern hätten führen können, strukturell verhindert werden konnten. Traten dennoch Fehlermeldungen auf, geschah dies nur dann, wenn das GUI selbst 9 Als Widgets werden die grundlegenden Elemente einer graphischen Benutzeroberfläche bezeichnet. Widgets wären zum Beispiel Menüleisten (menubar) und -einträge (menu), Schaltknöpfe (button), Radioknöpfe (radio button), Eingabezeilen (entry), Rollbalken (scrollbar), aber auch nicht interaktive Elemente wie Rahmen (frame) oder Beschriftungen (label). Widgets können zu größeren, zusammenarbeitenden Einheiten zusammengesetzt werden und so neue Funktionalitäten darstellen. Jegliche Interaktionen der X-Window-Umgebung werden über Widgets realisiert. Die Widgets des OSF-Motif-Systems und ihre Abhängigkeiten werden ausführlich in [5], S. 232 beschrieben. 10 Die XLib ist eine Sammlung von Datenstrukturen und Funktionen, die eine Nutzung der Funktionalitäten des X-Window-Systems ermöglicht. 11 Ioi Kim Lam, The Tix Widget Set”, [email protected], keine weiteren Angaben verfügbar 12 Eine sehr umfassende Beschreibung der Konzepte zur Gestaltung und Programmierung von graphischen Benutzeroberflächen bietet [13] S. 289ff. Dabei werden auch die psychologischen Grundlagen und Ergonomieaspekte eingehend erörtert. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 123 oft unentdeckte oder unvermutete logische Widersprüche enthielt. Das Aufdecken dieser Widersprüche führte zu einem Programm, in dem zu jedem Zeitpunkt nur tatsächlich benutzbare Funktionalitäten dem Benutzer zur Verfügung stehen, während potentiell fehlerhafte oder zu bestimmten Zeitpunkten unzulässige nicht auswählbar sind. Zum Beispiel ist das Verbinden mit einem Server nur ganz am Anfang nach dem Programmstart sinnvoll. Die Entscheidung, mit welchem Server sich der Benutzer verbinden will, kann diesem nicht abgenommen werden. Dennoch kann xLDB überprüfen, ob überhaupt eines der vorgesehenen LDB-Serverprogramme auf dem entsprechenden Rechner läuft. Im übrigen dürfen alle Operationen an der LDB erst nach dem Anmelden bei der LDB für den Benutzer erreichbar sein. Also ist beim Start von xLDB neben dem Menüpunkt zum Verlassen des Programms, dem Anzeigen der Informationsfenster und dem Auskunftsdialog nur der Menüpunkt ServerkConnect13 mit den Alternativen ServerkConnectkSol und ServerkConnectkSaturn erreichbar. Ist einer der aufgeführten Server nicht erreichbar, wird sein Menüeintrag deaktiviert. Der gesamte Menüeintrag Connect ist nach dem erfolgreichen Anbinden an einen Server nicht mehr erreichbar, stattdessen aber die anderen Einträge dieses und der anderen Menüs (je nach Rechte-Status des Benutzers). Die Möglichkeit, bestimmte Menüs, Fenster, Knöpfe oder andere Eingabeelemente bedienbar oder abgeschaltet zu gestalten, stellt das mächtigste Kontrollmittel eines Programmierers von GUIs dar. Darin wird er durch TCL/TK voll unterstützt. xLDB bildet mit seinen Menüs und Fenstern nicht alle tatsächlichen Befehle der LDB nach, sondern bildet diese Befehle, zum Teil vom Benutzer unbemerkt, in die Funktionen des Lexikon-Edierens ab. Das Abbilden von Datenbankfunktionen, die schlüssel-index-orientiert sind, auf Edierfunktionen, die lexikoneintragsorientiert sind, ist eine der grundlegenden Aufgaben von xLDB. Nur ein Beispiel. Will der Benutzer einen existierenden Lexikoneintrag verändern, drückt er einfach auf den Knopf EditkModify des gerade angezeigten Lexikoneintrags. Im Hintergrund wird xLDB zuerst den Eintrag in der LDB sperren (und dabei die Gültigkeit der Operation überprüfen) und dann den betreffenden Eintrag erneut laden, so daß immer die aktuellste Version eines Eintrags bearbeitet wird. Nach dem Verändern wird xLDB den Eintrag unter dem richtigen Schlüssel und virtuelDarstellung Menüeintrag1kMenüeintrag2 soll bedeuten, daß Menüeintrag2 ein Untereintrag zu Menüeintrag1 ist. Dieselbe Notation wird auch verwendet, um einen Knopf in einer Gruppe von Knöpfen zu beschreiben. 13 Die KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 124 len Index in die LDB zurückspeichern, die Sperrung aufheben und den veränderten Eintrag erneut zur Ansicht in xLDB von der LDB einlesen. Die 4 Vorgänge für die LDB (Sperren, Lesen, Ersetzen, Entsperren) werden durch zwei Knopfdrücke für den Benutzer abgearbeitet. Während des ganzen Vorgangs muß der Benutzer weder Nachfragen beantworten noch sich darum kümmern, daß die xLDB immer das gleiche Schlüssel-Index-Paar verwendet, geschweige denn irgendwelche Tastatureingaben vornehmen (außer natürlich für inhaltliche Änderungen am Lexikoneintrag). Dieses Vorgehen schließt Tippfehler und logische Inkonsistenzen in der Kommunkikation mit der LDB strukturell aus. 8.3.3 Die Anforderungen an xLDB Die Forderungen, die xLDB zu erfüllen hat, kann man in zwei Bereiche aufteilen: Anforderungen an die Netzwerkschnittstelle Diese wurden schon in Abschnitt 7.3 aufgelistet; deshalb soll hier darauf verzichtet werden. Anforderungen an die Schnittstelle zum Benutzer Dies ist die Beschreibung der Benutzeroberfläche. Damit xLDB überhaupt die LDB ansprechen kann, muß ein RPC-fähiges Clientprogramm zum Absetzen der Datenbankanfragen und zum Auswerten der Antworten des LDB-Serverprogramms zum Einsatz kommen. Diese Aufgabe übernimmt in xLDB das im obigen schon beschriebene Kommandozeilenprogramm ldbcall. Wie xLDB die durch den Benutzer angeforderten Datenbankanfragen an die LDB übermittelt zeigt Abbildung 8.1. Die aufgestellten Forderungen lassen sich für die Implementation von xLDB in folgende Einzelforderungen aufteilen: Anbindung an den Server herstellen Verbindung zum Server lösen Berücksichtigung und Darstellung der Beschränkungen bei den verschiedenen Benutzergruppen durch geeignetes Aktivieren bzw. Deaktivieren von z.B. Menüeinträgen KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME ProgrammInitialisierung HauptEreignisSchleife 125 xLDB exec Befehlsumsetzung RPC ldbcall Programmabschluß Abbildung 8.1: Schematische Darstellung der Verbindung zwischen xLDB und LDB über das Programm ldbcall Darstellung der Informationen, die der Server mit seinen Auskunftsfunktionen zur verfügung stellt, im einzelnen Informationen – zum Serverbetriebszustand – zu den gerade angemeldeten Benutzern – zu der gerade geöffneten (oder nicht-geöffneten) Datenbank. Funktionen, um Lexikoneinträge in der LDB zu suchen, zu verändern oder zu löschen Funktionen, um Lexikoneinträge aus der LDB in eine Datei auszugeben bzw. aus einer Datei in die LDB aufzunehmen. Funktionen, um die Datenbank als solche zu manipulieren (öffnen, Schließen, Löschen, Defragmentieren) Funktionen, um den Server zu manipulieren (Shutdown, Fehlermeldungen abfragen) Alle diese Funktionen sind in xLDB dem Benutzer über verschiedene Bedienelemente zugänglich. Die wesentlichen Bedienelemente sollen im folgenden Abschnitt an einer beispielhaften Sitzung mit xLDB erklärt werden. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 126 8.3.4 Eine Sitzung mit xLDB 8.3.4.1 D ER S TARTBILDSCHIRM UND DIE M EN ÜZEILE Nach dem Programmstart mit dem Shellkommando xLDB zeigt sich dem Benutzer die in Abbildung 8.2 dargestellte Menüzeile. Abbildung 8.2: Der Startbildschirm xLDBs Soweit nicht anders vermerkt, soll für die folgende Abschnitte angenommen werden, daß der Benutzer mindestens einen privilegierten Benutzerstatus hat. In dieser Menüzeile sind nur die Menüpunkte aktiviert, die das Aussehen des xLDB-Programms bestimmen oder das Aufbauen der Verbindung an einen LDBServer ermöglichen. Es wäre nicht sinnvoll andere Aktionen zuzulassen. Der Benutzer kann hier das Programm wieder verlassen, sich Auskunft über die aktuelle Version und eine Kurzbeschreibung des Programms geben lassen oder die Verbindung zu einem LDB-Server aufbauen. Nachdem die Verbindung zum LDB-Server aufgebaut ist, werden dem Benutzer unterhalb der Menüzeile Informationen über den Namen des LDB-Serverrechners, den Rechtestatus des Benutzers im LDB-Server und, wenn eine Datenbank geöffnet ist, der Name der Konfigurationsdatei und der Basisname der Datenbank angezeigt. Darunter befindet sich die Statuszeile, die Auskunft über den Systemzustand xLDBs gibt. Der Benutzer wird beim Aufbauen der Verbindung zu LDBServerprogramm automatisch von xLDB bei diesem angemeldet. Genauso erfolgt auch die Abmeldung vom LDB-Serverprogramm automatisch beim ordnungsgemäßen Verlassen des xLDB-Programms. Sollte keine Datenbank geöffnet sein, kann der Benutzer, wenn er RootBenutzerrechte hat, über den jetzt zugänglichen Menüeintrag DatabasekOpen eine Konfigurationsdatei auswählen, über die das LDB-Serverprogramm die entsprechende Datenbank öffnet. Wenn eine Datenbank geöffnet ist, erscheint unterhalb der Menü- und Informati- KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 127 onszeile ein weiteres Fenster, das Eingabefenster. Wichtige Bedienelemente sind neben der Eingabezeile die darunterliegenden Knöpfe mit einem nach links und einem nach rechts zeigenden Pfeil. Über die Eingabezeile des Eingabefensters kann der Benutzer den Suchschlüssel des gewünschten Lexikoneintrags eingeben. Dieser wird durch Drücken des Knopfes EditkView vom LDB-Server angefordet und, wenn ein Eintrag zu diesem Schlüssel vorhanden ist, in einem nun erscheinenden, eigenen Fenster (Darstellungsfenster) graphisch angezeigt. Zur Veranschaulichung soll Abbildung 8.3 dienen, in der die eben beschriebene Aktion für den Schlüssel fliegen durchgeführt wurde. Abbildung 8.3: Darstellung eines Lexikoneintrags durch xLDB Mit den beschriebenen Pfeiltasten kann der Lexikoneintrag zum Vorgänger- bzw. Nachfolgerschlüssel des gerade angezeigten Lexikoneintrags von der Datenbank angefordert werden. Durch Drücken des Knopfes AllomorphskView wird der zum eingegebenen Such- KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 128 schlüssel gehörende Allomorpheintrag in einem eigenen Fenster dargestellt. Neben den Knöpfen zum Anzeigen von Lexikoneinträgen enthält das Eingabefenster noch einen Knopf zum Anlegen eines neuen Lexikoneintrags. Dies wird später beschrieben. 8.3.4.2 A NZEIGE EINES L EXIKONEINTRAGS Das oben erwähnte Fenster, in dem ein Lexikoneintrag dargestellt wird, teilt sich in vier verschiedene Zonen: die Beschreibung des Lexikoneintrags durch Angabe des Suchschlüssels, des virtuellen Index, und den Sperrzustand in der ersten Zeile die graphische Darstellung des Lexikoneintrags als Attribut-WerteKonstrukt14 in der Mitte links, die Anzeige der Kommentare zum Lexikoneintrag (links unten) und das Bedienfeld für Aktionen des Benutzers (rechte Spalte). Neben den vier beschriebenen Zonen teilt die Titelzeile des Fensters dem Benutzer mit, aus welcher Teildatenbank (Edit oder Allo) der angezeigte Lexikoneintrag stammt, wieviele Lexikoneinträge zu diesem Schlüssel gefunden wurden und der wievielte davon im aktuellen Fenster dargestellt wird. Ist der dargestellte Lexikoneintrag durch einen anderen Benutzer der LDB gesperrt, wird in der rechten oberen Ecke des Fensters ein geschlossenes Schloß sichtbar, anstelle des sonst geöffneten. Ist ein Eintrag gesperrt, werden die Knöpfe, mit denen der Eintrag verändert oder gelöscht werden kann, deaktiviert. Durch Drücken der rechten Maustaste über der Darstellung des Attribut-WerteKonstrukts erscheint ein Menü, über das die verschiedenen Einträge zu einem Suchschlüssel zugänglich sind. Nach Auswählen eines Eintrags über seinen Unterschlüssel wird er in einem neuen, identisch aussehenden Fenster dargestellt. Der angezeigte Lexikoneintrag kann vom Benutzer über den Knopf EditkModify... geändert oder über den Knopf EditkRemove... aus der Datenbank gelöscht werden. Der Benutzer kann sich durch Drücken des Knopfes AllomorphskView alle 14 Die Anzeige der Attribut-Werte-Konstrukte erfolgt mit Hilfe eines erst vor kurzem in der Compuerlinguistik Erlangen entwickelten, erweiterten Canvas-Widgets. Dazu wurde eine neue TKShell mwish implementiert. Die Implementation des Widgets durch mwish ist Teil des MALAGAProjektes. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 129 zu diesem Lexikoneintrag erzeugten Allomorphe anzeigen lassen. Diese werden daraufhin in eigenen Fenstern dargestellt. Nach dem Betätigen des Knopfes CommentkAdd... kann der Benutzer einen einzeiligen Kommentar zum angezeigten Lexikoneintrag hinzufügen. Als Besonderheit ist die Funktion, die sich hinter dem Knopf EntrykTo clipboard verbirgt, zu erwähnen. Wird dieser Knopf betätigt, dann wird der dargestellte Lexikoneintrag in seiner Textform in den Selectionbuffer des X-Window-Systems kopiert, so daß der Eintrag dann in ein beliebiges anderes X-Window-Programm durch Auslesen des Selectionbuffers übernommen werden kann. Dies geschieht im allgemeinen durch simples Drücken der mittleren Maustaste. Dadurch ist es möglich Lexikoneinträge in einem xLDB-externen Programm zu manipulieren und auf einfache Weise wieder in xLDB zu importieren. Mit dem Knopf EntrykClose wird das Lexikoneintragsfenster geschlossen. Werden alle Lexikoneinträge zu einem Suchschlüssel einschließlich aller aus ihnen erzeugten Allomorpheinträge gleichzeitig dargestellt, können sich gut ein Dutzend Fenster auf dem Bildschirm “tummeln”. Um nicht jedes Fenster einzeln schließen zu müssen, können über den Eintrag WindowskClose all Edit Windows bzw. WindowskClose all Allo Windows alle entsprechenden Fenster auf einmal geschlossen werden. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 8.3.4.3 A NLEGEN EINES NEUEN ODER Ä NDERN EINES BESTEHENDEN 130 L EXI - KONEINTRAGS Zum Ändern eines bestehenden Lexikoneintrags bzw. zum Anlegen eines neuen wird in beiden Fällen das gleiche Texteingabefenster verwendet, so daß beide Vorgänge gemeinsam beschrieben werden können. Soll ein neuer Lexikoneintrag erzeugt werden, drückt der Benutzer im Eingabefenster den Knopf EditkCreate new. Um einen bestehenden Eintrag zu modifizieren, drück man im Darstellungsfenster des zu ändernden Lexikoneintrags den Knopf EditkModify.... Dem Benutzer wird dann ein Texteingabefenster zur Verfügung gestellt. Abbildung 8.4: Das Texteingabefenster zum Modifizieren bzw. Neuanlegen eines Lexikoneintrags mit aufgeklapptem Schablonenmenü Wenn der Benutzer einen bestehenden Eintrag ändert, wird der bisherige Eintrag KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 131 in der LDB gesperrt und erneut eingelesen, so daß der Benutzer wirklich den für ihn gesperrten Eintrag bearbeitet. Der Eintrag wird dann als “Ausgangsmaterial” in das Texteingabefenster kopiert. Dies zeigt Abbildung 8.4. Wird ein neuer Eintrag erzeugt, ist das Texteingabefenster leer. Wie im letzten Absatz des Abschnitts 6.4.2 schon erläutert wurde, haben viele Einträge eines Lexikons eine untereinander ähnliche Eintragsstruktur. Dadurch könnte das Lexikon mit Hilfe einiger weniger Schablonen, die nur um die sich unterscheidenden Teile des Lexikoneintrags (z.B. die Oberfläche der Wortform) ergänzt werden, beschrieben werden. Um dieser Eigenschaft des Lexikons gerecht zu werden, wurde im Texteingabefenster von xLDB ein Schablonenmenü vorgesehen. Der Lexikon kann sich in der Schablonendatei .template in seinem HOME-Verzeichnis Mustereinträge, die o.g. Schablonen, zusammenstellen, die über das Schablonenmenü in das Texteingabefenster eingefügt werden können. In der Schablonendatei können beliebige Zeichenfolgen mit einem Namen versehen werden, der im Schablonenmenü eingetragen wird. Will der Benutzer den edierten Eintrag in die Datenbank einfügen, drückt er den OK-Knopf, woraufhin xLDB dem LDB-Serverprogramm den edierten Eintrag zuschickt. Wurde nur ein bestehender Lexikoneintrag modifiziert, so wird der ursprüngliche Eintrag in der Datenbank ersetzt. 8.3.4.4 DATEIOPERATIONEN IN xLDB Sollen Lexikoneinträge aus einer Datei in die LDB eingelesen werden oder der Inhalt einer der Teildatenbanken komplett in eine Datei ausgegeben werden, stellt xLDB diese Funktionen unter den Menüeinträgen DatabasekImport... und DatabasekExport zur Verfügung. Das Vorgehen ist für beide Vorgäng das gleiche. Der Benutzer wählt in einem Dateiauswahldialog die zu bearbeitende Datei bzw. die Datei in die der Datenbankinhalt ausgegeben werden soll aus. xLDB übergibt den ausgewählten Dateinamen dem LDB-Serverprogramm. Alle Bedienelemente xLDBs bleiben während des Vorgangs, der beim Einlesen von Lexikoneinträgen aus einer Datei durchaus längere Zeit dauern kann, gesperrt. 8.3.4.5 F EHLERMELDUNGEN Die Fehlermeldungen des LDB-Serverprogramms bzw. des xLDB zugrundeliegenden Clientprogramms ldbcall werden von xLDB in eine Klartextfehlermedlung umgesetzt und dem Benutzer in einem Nachrichtendialog sofort mitgeteilt. KAPITEL 8. BESCHREIBUNG DER ERSTELLTEN PROGRAMME 132 8.3.5 Kompatibilität Die Anzeige der Lexikoneinträge in xLDB erfolgt unter Verwendung eines modifizierten Canvas-Widgets. Die Modifikationen wurden in C implementiert und verleihen dem Canvas die Fähigkeit Attribut-Werte-Konstrukte darzustellen. Damit ist der Einsatz von xLDB auf das Vorhandensein des modifizierten Canvas-Widgets angewiesen. Dieses liegt nur im veränderten TK-Befehlsinterpreter mwish vor, der im Rahmen des MALAGA-Projekts aus dem normalen TK-Interpreter wish entwickelt wurde vor. xLDB ist dadurch nicht auf jedem beliebigen TCL/TK-System lauffähig. xLDB wurde unter der TCL-Version 7.3b und der TK-Version 3.6 implementiert. Das zusätzlich verwendete Tix Widget Set wurde in der Version 3.6d verwendet. Kapitel 9 Zusammenfassung Das morphologische und syntaktische Analyse- und Generierungssystem MALAGA verwendet ein umfangreiches Lexikon als Datenbasis. Für die Arbeit mit MALAGA muß das Klartextlexikon in mehreren Schritten in Laufzeitdatenstrukturen (Allomorpheinträge) umgewandelt werden. Diese Umwandlungsschritte sind sehr zeitintensiv, da nach Änderungen und Erweiterungen am Lexikon immer das gesamte Lexikon (mit z.Z. ca. 20.000 Einträgen) umgewandelt werden muß. Die vorliegende Arbeit wurde mit dem Anspruch in Angriff genommen, Verbesserungen und Erweiterungen des Lexikons schneller und sicherer vornehmen zu können, so daß die geänderten Lexikondaten dem Analysesystem in kürzerer Zeit wieder zur Verfügung stehen. Dazu war es nötig, die bestehende Verwaltung des Lexikons, das in einigen Dateien abgelegt war, auf eine Lexikonverwaltung mit einer Lexikondatenbank (LDB) umzustellen. Diese Umstellung löst mehrere Probleme der früheren Vorgehensweise und eröffnet dem Lexikonbearbeiter eine neue Sicht auf das Lexikon. Die in dieser Arbeit implementierte LDB ermöglicht es einem Lexikonbearbeiter, nach Lexikoneinträgen zu suchen, diese zu modifizieren, zu speichern oder zu löschen. Desweiteren kann der Lexikonbearbeiter mit Hilfe der LDB die bei den Umwandlungschritten erzeugten Daten (Allomorpheinträge) eintragsweise im Klartext sichten. Dies war bisher nicht möglich, da die Allomorpheinträge als Binärcode abgespeichert waren. Der Erfolg der regelbasierten Allomorphgenerierung und damit die Richtigkeit der Allomorphregeln konnte erst indirekt durch die Analyse mit MALAGA festgestellt werden. Daneben ist es mit der LDB erstmals möglich, die am Lexikon getätigten Verände- 133 KAPITEL 9. ZUSAMMENFASSUNG 134 rungen zu dokumentieren und die Entwicklung des Lexikons nachzuvollziehen. Die LDB erzeugt automatisch Kommentare zu jedem Lexikoneintrag. Daneben können Lexikonbearbeiter eigene Kommentare zu jedem Eintrag anbringen. Die LDB ist ein Datenlieferant für MALAGA. Deshalb orientieren sich die Konzepte der LDB an den Abhängigkeiten zwischen den verschiedenen Lexikoneintragstypen in MALAGA. Die Lexikoneinträge und ihre Abhängigkeiten können am besten mit einer Netzwerkdatenbank repräsentiert werden. (Kapitel 3 und 5). Um das linguistische Wissen, das im Lexikon repräsentiert wird, möglichst von der Verwaltung der Lexikondaten zu trennen, wurde ein Konzept von externen Filterprogrammen eingesetzt. Dieses erlaubt eine Aufbereitung der Lexikoneinträge außerhalb der LDB (Abschnitt 6.2). Durch die Verwaltung der Lexikon- und Laufzeitdaten mit der LDB, die diese Daten nicht mehr für jeweils das gesamte Lexikon, sondern nur noch für die tatsächlich veränderten Lexikoneinträge erzeugt, wurde hier eine erhebliche Verkürzung der Turnaround-Zeiten herausgearbeitet. Lexikonbearbeiter erhalten durch die Verwendung von Remote Procedure Calls über das Netzwerk Zugriff auf die LDB. Das implementierte Client-ServerKonzept ermöglicht mit Hilfe eines lexikoneintragsbezogenen Sperrkonzepts das gleichzeitige Bearbeiten des Lexikons durch mehrere Benutzer, ohne daß diese sich gegenseitig in für das Lexikon destruktiver Weise beeinträchtigen können. Dies schließt ein gegenseitiges Überschreiben eines Lexikoneintrags durch mehrere Benutzer aus (Kapitel 7). Die Zugangsberechtigung der Benutzer zur LDB wird über UNIX-Gruppenrechte geregelt. Die LDB unterscheidet Benutzer mit drei verschiedenen Prioritäten. Um Benutzern die ihnen zukommenden LDB-Server-Dienste richtig zuteilen zu können, wurde eine Benutzerverwaltung implementiert (Abschnitt 5.6). Die LDB setzt sich aus mehreren Teildatenbanken zusammen. Zum Zugriff auf unterster Ebene implementieren die Teildatenbanken einen B-Baum (Bayer-Baum), über den unter Verwendung eines zusammengesetzten Suchschlüssels auf die Datensätze (Lexikoneinträge) zugegriffen werden kann (Abschnitt 6.1). Bei Lexika in natürlicher Sprache teilen sich oft mehrere Lexikoneinträge denselben Suchschlüssel. Dieser Widerspruch zur Forderung eines eindeutigen Suchschlüssels wurde in der LDB durch die Verwendung eines zusammengesetzten Schlüssels, bestehend aus einer Zeichenkette und einem Subindex, gelöst. Die Länge der in den Teildatenbanken verwendeten Suchschlüssel und Datensätze KAPITEL 9. ZUSAMMENFASSUNG 135 ist nicht begrenzt, und der Speicherplatz für diese Daten wird dynamisch verwaltet. Der größte Teil der Zugriffsstrukturen wird im Vordergrundspeicher gepuffert, so daß auch bei größeren Datenmengen ein effizienter Zugriff auf die Datensätze gewährleistet ist. Als Ergebnis dieser Arbeit liegen drei Programme vor: ldb, das LDBServerprogramm; ldbsh, eine interaktive Shell, um auf die LDB zuzugreifen; das Programm ldbcall ist eine Kommandozeilenversion der Shell; xLDB, eine graphische Benutzeroberfläche. Mit xLDB wurde unter Verwendung der Programmiersprache TCL/TK eine graphische Benutzeroberfläche geschaffen, mit der dem Lexikonbearbeiter ein vereinfachter und weitgehend von Eingabefehlern geschützter Zugriff auf die LDB entsprechend dem Rechtestatus des Benutzers ermöglicht wird (Abschnitt 8.3). 9.1 Mögliche Verbesserungen Verbesserungen an der LDB können in mehreren Bereichen vorgenommen werden. Die Pufferung der Schlüsselsatztabellen erfolgt z.Z. noch über ein Pufferkonzept vollständig im Vordergrundspeicher und ist damit der größte Einzelspeicherverbraucher der LDB. Das Pufferkonzept sollte sich mit kalkulierbarem Aufwand in einen Filemapping-Mechanismus umwandeln lassen. Das Betriebssystem könnte dann je nach Systemzustand dem LDB-Serverprogramm dynamisch Pufferspeicher für die Schlüsseltabelle zuweisen. Die Ausgabe des Allomorphlexikons ist z.Z. noch nicht direkt durch MALAGA zu benutzen. Die von der LDB in eine Datei geschriebenen Allomorpheinträge müssten zuerst noch in ein durch MALAGA direkt verwendbares Format gewandelt werden. Diese Aufgabe liegt jedoch im gleichen Maße außerhalb der LDB wie die Filterprogramme der LDB und ist daher eher im Aufgabenbereich MALAGAs anzusiedeln. Als Lösung bietet sich eine Integration dieses Wandlungsprogrammes in MALFIL an. Um Zeichensysteme1 mit der LDB zu verwalten, die nicht auf ISO-Latin1oder ASCII basierende Zeichen repräsentieren, müßte unter anderem MultibyteZeichen-Verarbeitung an den entsprechenden Stellen der LDB nachgerüstet werden. Die Verwendung dieser Zeichen (Eingabe und Darstellung) gestaltet sich auch 1 Hier wird vor allem an die Darstellung koreanischer Schriftzeichen in Hangul gedacht, deren Verarbeitung mit MALAGA jetzt schon möglich ist. KAPITEL 9. ZUSAMMENFASSUNG 136 unter TCL/TK schwierig. 9.2 Anschlußarbeiten xLDB könnte in seinem Texteingabefenster um eine Previewfunktion erweitert werden, indem ein Matrix-Canvas-Widget versucht, den eben erst geschriebenen neuen Lexikoneintrag graphisch darzustellen. Dann würden syntaktische Fehler schon während der Eingabe in xLDB und nicht erst in der LDB erkannt werden. Die ldbsh könnte um Befehle erweitert werden, die das Suchen in Datensätzen ermöglichen, um gezielt in den Lexikoneinträgen der LDB nach Attributen und Werten suchen zu können. In fernerer Zukunft wäre eine Eingabe der Attribut-Wert-Konstrukte auf graphischer Basis wünschenswert. Der Abhängigkeit der LDB von den Allomorphregeln könnte dadurch Rechnung getragen werden, daß die Allomorph- und vielleicht auch die Kombinationsregeln über einen graphischen Editor erstellt und in einer Regeldatenbank verwaltet werden. Man könnte sich vorstellen, auf diese Weise im Laufe der Zeit eine integrierte, modulare Entwicklungsumgebung für die Entwicklung, Bearbeitung und Nutzung von Grammatiken, Lexika und Korpora auf der Basis des MALAGA-Systems zusammenzustellen. Literaturverzeichnis [1] Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman. Data Structures and Algorithms. Addison-Wesley Publishing Company, Reading, Massachusetts, 1983. [2] Adrian Akmajian, Richard A. Demers, and Robert M. Harnish. Linguistics. The MIT Press, Cambridge, Massachusetts, 2 edition, 1984. [3] Björn Beutel. MALAGA, Eine Sprache zur Implementierung Linksassoziativer Grammatiken. FAU Erlangen, Institut für Deutsche Sprach- und Literaturwissenschaft, Abteilung Computerlinguistik, 1995. [4] Morris I. Bolsky and David G. Korn. The Kornshell. Prentice Hall International (UK) Limited, London, 1989. [5] Hans Joachim Brede, Nicolai Josuttis, Sabine Lemberg, and Achin Lörke. Programmieren mit OSF/Motif. Addison-Wesley (Deutschland) GmbH, München, 1991. [6] Norbert Bröker. Optimierung von LA-Morph im Rahmen einer Anwendung auf das Deutsche. Diplomarbeit an der FAU Erlangen, IMMD - Lehrstuhl für Programmiersprachen, 1991. [7] Hadumod Bußmann. Lexikon der Sprachwissenschaft. Alfred Kröner Verlag, Stuttgart, 1990. [8] C. J. Date. An Introduction to Database Systems, Vol. I. Addison-Wesley Publishing Company, Reading, Massachusetts, 1990. [9] Ferdinand de Saussure. Cours de linguistique générale. Éditions Payot, Paris, 1985. [10] Marc Domenig. Entwurf eines dedizierten Datenbanksystems für Lexika. Max Niemeyer Verlag, Tübingen, 1987. 137 LITERATURVERZEICHNIS 138 [11] Ramez Elmasri and Shamkant B. Navathe. Fundamentals of Database Systems. The Benjamin/Cummings Publishing Company, Inc., Redwood City, California, 1989. [12] Herrmann Engesser. DUDEN Informatik. F.A. Brockhaus AG, Mannheim, 1988. [13] Dieter Geiss and Jürgen Geiss. Vom Anfänger zum GEM-Profi. Hüthig Buch Verlag GmbH, Heidelberg, 1991. [14] Roland Hausser. NEWCAT: Parsing Natural Language Using LeftAssociative Grammar. Springer Verlag, Berlin Heidelberg New York, 1986. [15] Roland Hausser. Computation of Language. Springer Verlag, Berlin Heidelberg New York, 1989. [16] Roland Hausser. Grundlagen der computer-linguistik. Vorläufige Version des Vorlesungsskripts, FAU Erlangen-Nürnberg, 6 1995. [17] Hewlett-Packard. Programming and Protocols for NFS Services. HewlettPackard Company, Corvallis, USA, 1991. [18] Hewlett-Packard. Using the X Window System. Hewlett-Packard Company, Corvallis, USA, 5 edition, 1991. [19] Dirk Honekamp and Peter Wilken. Windows 3.1. München, 1992. [20] Rainer Klar. Digitale Rechenautomaten. Walter de Gruyter & Co., Philippines, 4 edition, 1989. [21] Donald E. Knuth. The Art of Computer Programming. Addison-Wesley Publishing Company, Inc., Philippines, 1973. [22] Theodor Lewandowski. Linguistisches Wörterbuch 2. Quelle & Meyer Verlag, Heidelberg, 5 edition, 1990. [23] John K. Ousterhout. Tcl and the Tk Toolkit. Addison-Wesley Publishing Company, Reading, Massachusetts, 1994. [24] Mike Papazoglou and Wilhelm Valder. Entwurf relationaler Datenbanken in C. Carl Hanser Verlag, München, Wien, 1992. [25] Marc J. Rochkind. UNIX-Programmierung für Fortgeschrittene. Carl Hanser Verlag, München, Wien, 1991. LITERATURVERZEICHNIS 139 [26] Michael Santifaller. TCP/IP und NFS in Theorie und Praxis. Addison Wesley (Deutschland) GmbH, München, 1991. [27] Gerald Schüller and Burkhard Stubert. Die Programmiersprache M1. Begleitschrift zum Hauptseminar: Automatische Analyse und Interpretation syntaktischer Strukturen. FAU Erlangen, Institut für Deutsche Sprach- und Literaturwissenschaft, Abteilung Computerlinguistik, 1994. [28] Gerald Schüller, Marco Zierl, and Roland Hausser. MAGIC, A Tutorial in Computational Morphology. FAU Erlangen, Institut für Deutsche Sprachund Literaturwissenschaft, Abteilung Computerlinguistik, 1993. [29] Michael A. Schoonover. GNU Emacs, UNIX Text Editing and Programming. Addison Wesley Publishing Company, Reading, Massachusetts, 1992. [30] Jörg Schreiber. Formalgrammatische Beschreibung und automatische Analyse von Verbalkomplexen in der deutschen Sprache. Magisterarbeit an der FAU Erlangen, Institut für Deutsche Sprach- und Literaturwissenschaft, Abteilung Computerlinguistik, 1995. [31] Otto Springer. Langenscheidts Enzyklopädisches Wörterbuch. scheidt, Berlin, München, Wien, Zürich, 1990. Langen- [32] Richard Stallman. GNU Emacs Manual - Version 18. Free Software Foundation, Cambridge, Massachusetts, USA, 1991. [33] W. Richard Stevens. Programmieren von UNIX-Netzen. Carl Hanser Verlag, München, wine, 1991. [34] W. Richard Stevens. Advanced Programming in the UNIX Environment. Addison Wesley Publishing Company, Reading, Massachusetts, 1992. [35] Unbekannt. GZIP UNIX Manual Page Version 1.2.4. Free Software Foundation, 1995. [36] Niklaus Wirth. Algorithmen und Datenstrukturen mit Modula-2. B.G.Teubner, Stuttgart, 1986. [37] J. Ziv and A. Lempel. A universal algorithm for sequential data compression. In IEEE Transactions on Information Theory, volume 23 of 3, pages 337– 343, 1977. LITERATURVERZEICHNIS 140 Wahrheitsgemäße Erklärung Ich erkläre hiermit, daß ich 1. die eingereichte Abhandlung selbständig und ohne unerlaubte Hilfe angefertigt habe, 2. außer den im Schrifttumsverzeichnis angegebenen Hilfsmitteln keine weiteren benutzt und alle Stellen, die aus dem Schrifttum ganz oder annähernd entnommen sind, als soche kenntlich gemacht und einzeln nach ihrer Herkunft unter Bezeichnung der Ausgabe (Auflage und Jahr des Erscheinens), des Bandes und der Seite des benützten Werkes in der Abhandlunga nachgewiesen habe, 3. alle Stellen und Personen, welche mich bei der Vorbereitung und Anfertigung der Abhandlung unterstützten, genannt habe, 4. die Abhandlung noch keiner anderen Stelle zur Prüfung vorgelegt habe und daß dieselbe noch nicht anderen Zwecken – auch nicht teilweise – gedient hat.