History: DanielKinzler Chapter 7: Framework
View page
Source of version: 1
(current)
7. Framework In den vorangegangenen Kapiteln wurde ein grober Entwurf für die Funktionalität von WikiWord entwickelt (.3) und die zu bewältigenden Aufgaben sowie die zu berücksichtigenden Rahmenbedingungen spezifiziert (.5). Dieses Kapitel gibt nun einen Überblick über die zu diesem Zweck entwickelten Softwarekomponenten (siehe Anhang G für Zugang zum Quellcode). Eine Beschreibung der Kommandozeilenschnittstelle für WikiWord findet sich in Anhang B. 7.1. Import-Architektur Dieser Abschnitt gibt eine Übersicht über die wichtigsten Klassen und Komponenten von WikiWord. Im Zentrum der Betrachtung steht dabei ImportConcepts, das Programm zur Extraktion der Thesaurusdaten aus dem Wiki-Text. Die Programme, die die Kommandozeilenschnittstelle vonWikiWord bilden, sowie die Parameter und Optionen für ihren Aufruf sind in Anhang B beschrieben. Weitere Möglichkeiten zur Konfiguration bieten die sogenannten Tweak-Werte, siehe .B.5. Eine Auflistung der relevanten Klassen und Packages ist in .G gegeben. Die Basis für alle Programme der Kommandozeilenschnittstelle von WikiWord ist die Klasse CliApp: Sie stellt Basisfunktionalität unter anderem zur Verarbeitung von Kommandozeilenparametern und zur Ausgabe von Log-Nachrichten bereit. Alle in .B.1 erwähnten Import-Programme mit Ausnahme von ExportSkos, bauen auf der von CliApp abgeleiteten Klasse ImportApp auf: dieses bietet Unterstützung für die Verwendung des Agenda- Systems zur Ablaufkontrolle (siehe Anhang B.6) sowie für die Erzeugung eines geeigneten Datenzugriffsobjektes für die Interaktion mit der Datenbank (siehe .C.3). Eine genauere Betrachtung verdient die Klasse ImportDump, auf der auch ImportConcepts basiert, welches der Einstiegspunkt für einen Großteil der Extraktionslogik ist. ImportDump ist von ImportApp abgeleitet und bildet das Framework für eine Consumer-Producer-Architektur für den Import von Daten: Eine Implementation des Interfaces ImportDriver liest „Seiten“ aus einer Datenquelle und übergibt sie, eine nach der anderen, an eine Implementation des Interfaces WikiWordImporter, die die Daten dann weiter verarbeitet. Die Klasse AbstractImporter bildet die Basis für Implementationen dieses Interfaces und bietet Funktionen insbesondere für die Ablaufsteuerung über das Agenda-Objekt sowie für die Umsetzung allgemeiner Kommandozeilenparameter. Im Normalfall sollen die Wiki-Seiten aus einem Wikipedia-Dump gelesen werden [MW:XML]. Dies wird von der Klasse DumpImportDriver umgesetzt (einer Implementation des Interfaces ImportDriver), die ihrerseits auf die MWDumper-Bibliothek von Wikimedia zurückgreift [MW:DUMPER]: Sie verarbeitet die XML-Struktur und ruft für jede enthaltene Wiki-Seite die Methode handlePage auf dem WikiWordImporter auf. Dabei wird die XML-Datei automatisch dekomprimiert, sollte dies erforderlich ein1. 1Unterstützt werden die weit verbreiteten Formate GZip und BZip2. 7. Framework 38 Für die Analyse des Wiki-Textes und den Import der so gewonnenen Ressourcen in das lokale Datenmodell verwendet das Programm ImportConcepts die Klasse ConceptImporter als Implementation von WikiWordImporter. Diese überführt den rohen Wiki-Text zunächst unter Verwendung von WikiTextAnalyzer in das Ressourcenmodell (siehe .4.1, .8, .D.1), interpretiert die Eigenschaften der Ressource (.4.2, .9.1) und schreibt das Ergebnis dann in das lokale Datenmodell, ein Datenzugriffsobjekt des Typs LocalConceptStoreBuilder (siehe und .C.4). Die Interaktion von DumpImportDriver, ConceptImporter, WikiTextAnalyzer und LocalConceptStoreBuilder wird im nächsten Abschnitt genauer erläutert. 7.2. Ablauf und Parallelisierung (Pipeline) main:DumpImportDriver read read read imperter:ConceptImporter handlePage handle (queue) handlePage handle (queue) handlePage handle (queue) flusher:DatabaseLocalStoreBuilder store (buffer) flush store store (buffer) Abb. 7.1: Parallelisierung: die Import-Pipeline Die Aufgabe von ImportConcepts lässt sich in zwei Abschnitte gliedern: den eigentlichen Datenimport, also das Lesen, Interpretieren und Speichern der Daten, und die Nachbereitung, also die Konsolidierung der Daten. Der Datenimport ist selbst in mehrere Schritte gegliedert, von denen einige parallel ausgeführt werden können—diese Parallelisierung soll hier näher beschrieben werden. Die am Datenimport beteiligten Komponenten sind DumpImportDriver, ConceptImporterWikiTextAnalyzer und LocalConceptStoreBuilder bzw. DatabaseLocalConceptStoreBuilder. Diese Komponenten arbeiten zum Teil parallel (siehe Abb. 7.1) und sind wie folgt gekoppelt: Im Haupt-Thread des ImportConcepts-Programms wird die runImport-Methode von DumpImportDriver aufgerufen — sie ist der Einstiegspunkt für den gesamten Datenimport. DumpImportDriver extrahiert mit Hilfe der MWDumper-Bibliothek den Wiki-Text der einzelnen Seiten aus der XML-Struktur der Dump-Datei. Der Wiki-Text jeder Seite wird dann, zusammen mit der zugehörigen Metainformation wie dem Seitentitel, in eine Warteschlange eingefügt, aus der er, gemäß dem Consumer-Producer-Muster, von einem anderen Thread herausgenommen wird, der ihn dann an die Methode handlePage von ConceptImporter übergibt. Die Warteschlange ist auf n Einträge beschränkt: wenn sich schon n unbearbeitete Einträge in der Warteschlange befinden, wenn der Producer (DumpImportDriver) einen Eintrag 7. Framework 39 hinzufügen will, so wird dieser blockiert, bis der Consumer (ConceptImporter) einen Eintrag aus der Warteschlange entnommen hat. Die Länge der Warteschlange ist per Default 8 und kann über den Tweak-Wert dumpdriver.pageImportQueue konfiguriert werden — die Länge ist aber relativ unerheblich, da die Warteschlange in der Regel voll und der Producer-Thread blockiert ist. Die Warteschlange dient also nicht als Puffer, sondern lediglich der Entkopplung der beiden Aktivitäten, die eine parallele Ausführung erlaubt; eine Entkopplung nach dem Rendezvous-Muster wäre hier ebenfalls ausreichend. Wird dumpdriver.pageImportQueue auf 0 gesetzt, so wird der Import „durchgekoppelt“ und keine Warteschlange verwendet — in diesem Fall ruft der DumpImportDriver direkt die Methode handlePage von ConceptImporter auf. Wie oben beschrieben, wird der ConceptImporter in einem eigenen Thread betrieben und aus einer Warteschlange bedient. Für jeden Eintrag aus der Warteschlange wird die Methode handlePage mit dem Wiki-Text und den zugehörigen Metadaten wie dem Seitentitel aufgerufen. Diese Methode verwendet nun zunächst den WikiTextAnalyzer, um den Wiki-Text in das Ressourcenmodell, implementiert durch WikiTextAnalyzer.WikiPage (siehe .D.1), zu überführen, das heißt, den Text zu parsen und die relevanten Features (.4.1) wie Wiki-Links, verwendete Vorlagen etc. zu extrahieren. Die so bestimmten Eigenschaften werden dann interpretiert und entsprechende Informationen werden zur Speicherung an die Datenzugriffsschicht übergeben (siehe .9.1 und .C.4). Die datenbankbasierte Implementation der Datenzugriffsschicht (DAO), DatabaseLocalConceptStoreBuilder, verwendet intern für jede Datenbanktabelle einen Puffer, in dem neue Einträge zwischengespeichert werden. Ist ein Puffer voll, so wird er in eine Warteschlange gelegt und ein neuer Puffer für die betreffende Tabelle verwendet. Ein separater Thread arbeitet im Hintergrund die Puffer aus der Warteschlange ab, indem er einen nach dem anderen entnimmt und an die Datenbank weiterleitet. Das entspricht einer asynchronen Flush-Funktion für die Puffer. Bei einem expliziten Aufruf der Methode flush werden die Puffer aller Tabellen in die Warteschlange des Flush-Threads gelegt und dann gewartet, bis alle Daten in die Datenbank geschrieben wurden. Die Länge der Warteschlange für die asynchronen Flush-Funktion ist per Default 4 und kann über den Tweak-Wert dbstore.backgroundFlushQueue konfiguriert werden — die Länge ist aber relativ unerheblich, da die Warteschlange in der Regel leer sein sollte, da nur recht selten Einträge in ihr abgelegt werden. Sollte die Warteschlange häufig voll sein und damit den Arbeitsthread blockieren, sollte die Größe der Einfügepuffer erhöht werden — das kann über den Tweak- Wert dbstore.insertionBufferFactor geschehen. Dabei ist allerdings zu beachten, dass die Größe jedes einzelnen Puffers durch die MySQL-Konfigurationsvariable max_allowed_packet begrenzt ist — gegebenenfalls muss auch diese erhöht werden. Die Warteschlange dient also vornehmlich der Entkopplung der langwierigen Flush-Operation, so dass diese parallel zur Analyse des Wiki-Textes ausgeführt werden kann. Wird dbstore.backgroundFlushQueue auf 0 gesetzt, so wird die Flush-Operation „durchgekoppelt“ und keine Warteschlange verwendet — in diesem Fall muss der Arbeitsthread warten, während volle Einfügepuffer in die Datenbank übertragen werden. Werden die Tweak-Werte dbstore.useEntityBuffer und dbstore.useRelationBuffer auf false gesetzt, so wird für das Einfügen in die Datenbank gar kein Puffer benutzt, jeder Eintrag wird sofort übertragen. Dieser Modus ist allerdings sehr langsam und nur für die Fehlersuche sinnvoll.
SideMenu
Home Page
Demo screencast
Last changes
CLWE To do
Forum Wiki-translation
BabelWiki Workshop
Architecture document (pdf)
CLWE Paper (pdf)
Edit Side Menu
Latest Changes
No records to display
...more
Search
Find
Log In
Username:
Password:
I forgot my password
CapsLock is on.
Log in
Upcoming Events
No records to display