Blogsatz: Mit dem Engländer in die Cloud

1 Semester, 4503 Zeilen Code und 63 Commits später. Der letzte Unit-Test läuft endlich ohne Exception durch. Wie lange haben wir auf diesen Moment gewartet. Endlich fließen die Tupel in geordneten Bahnen durch das Netz. Aus URLs sind Float-Werte geworden. Doch fangen wir vorne an.

Nach der Ankündigung für das Masterprojekt Blogsatz im September letzten Jahres sind wir direkt zur Vorbesprechung gegangen. Uns haben vor allem die Themen Einsatz eines spezialisierten WebCrawlers und Speicherung und Verarbeitung semantifizierter Daten interessiert. Bei der Besprechung stellte sich allerdings heraus, dass zunächst grundlegendere Themen ausgearbeitet werden mussten. Diese haben wir im letzten Semester im Rahmen unseres Masterprojektes umgesetzt und möchten nun unsere Erfahrungen schildern.

Was war Blogsatz nochmal?

Durch das Blogsatz-Projekt sollen potentiell wissenschaftliche Blogs im Internet gefunden und nach deren wissenschaftlichem Gehalt bewertet werden.

Der Blog und der Blogpost

Die erste Aufgabe befasst sich mit der Erkennung und Extrahierung eines bzw. mehrerer Blogposts. Dazu muss man zunächst definieren, was ein Blogpost ist. Im Kontext von Blogsatz besteht ein Blogpost (im Netz) aus den folgenden Komponenten:

  • URI
  • Titel
  • HTML Inhalt

Das bedeutet, dass zunächst URI, Titel und der HTML Inhalt bekannt sein müssen, um die Daten eines Blogposts zu extrahieren. Als nächstes muss man definieren, was ein Blog ist. Ein Blog besteht aus den folgenden Komponenten:

  • URI
  • Liste von Blogposts

Da die meisten Blogs einen Atom- oder RSS-Feed besitzen, haben wir uns auf diese einfache Sichtweise geeinigt. Ein Feed stellt im wesentlichen genau diese Daten bereit. Jeden Eintrag in einem Feed fassen wir dabei als einen Blogpost auf.

Die Umsetzung

Zunächst wird der Atom- oder RSS-Feed vom Crawler entgegengenommen und ausgewertet. Jeder Eintrag im Feed wird als ein Blogpost interpretiert. Die URL des Blogposts wird an den Crawler gegeben, damit dieser den HTML Inhalt des Blogposts crawlen kann. Die übrigen Informationen wie Autor und Titel des Feedeintrages werden für die spätere Verwendung gespeichert.

Die Erkennung und Strukturierung eines Blogposts ist wesentlich schwieriger. Blogposts werden, im Gegensatz zu Feeds, vornehmlich geschrieben, um von Menschen gelesen zu werden. Für eine Maschine ist es daher wesentlich aufwendiger, die Struktur und den Inhalt eines in HTML serialisierten Blogposts zu erkennen. Die Strukturierung beschränkt sich daher auf die folgenden Aspekte des Blogposts, um die Erkennung so einfach wie möglich zu halten:

  • Inhalt des Blogposts (mitsamt Titel und Autor)
  • Kommentare zu diesem Blogpost (mitsamt Autor)

Für die Strukturierung geht man dabei in mehreren Schritten vor. Der erste Schritt transformiert die HTML Eingabe zu einer Baumstruktur mit HTML Elementen, dem sog. Document Object Model oder kurz DOM. Diese Aufgabe übernimmt in der Organizer-Komponente die Softwarebibliothek Jsoup. Jsoup erzeugt dabei ein DOM, das sehr nahe an der Baumstruktur ist, die auch von einem gängigen Webbrowser bei der Verarbeitung eines HTML Dokumentes erzeugt wird.

Blogpost und Kommentare in Baumstruktur (DOM)

Obwohl der Blogpost nun in einer Baumstruktur vorliegt, kann man nicht ohne weiteres der ganzen Struktur oder ganzen Teilbäumen zuordnen, ob diese zu dem Inhalt des Blogposts, zu einem Kommentar oder zu unwichtigem Inhalt gehören. Es kann z.B. vorkommen, dass Blätter und Knoten eines Teilbaums zu dem Inhalt des Blogposts gehören (in der Abbildung in orange dargestellt). Und ein Blatt dieses Teilbaumes zusammen mit anderen Blättern oder Knoten zu Kommentaren gehören (in der Abbildung in türkis dargestellt). Ein einfaches Beispiel dafür könnte sein:

Um dieses Problem zu lösen, greift man auf die Tiefensuche zurück. Mithilfe der Tiefensuche kann man in einer festgelegten Reihenfolge über alle Knoten des Baumes laufen. Nimmt man zusätzlich noch einen endlichen Automaten zur Hilfe, so kann man jedem Knoten, je nach Zustand des Automaten, einer der drei Kategorien “Blogpost”, “Kommentar” oder “unwichtig” zuordnen. Die drei Zustände dieses Automaten bezeichnen wir mit “post”, “comment” und “idle”.

Die Tiefensuche kann mit Jsoup auf der Baumstruktur mit einer Implementierung des Interface “NodeVisitor” durchgeführt werden. Für die Implementierung wurde auf eine SCXML-Implementierung aus dem Apache Commons Projekt zurückgegriffen. Der endliche Automat lässt sich so mit XML beschreiben, und einfacher Umsetzen und Testen.

Endlicher Automat

Die Erkennung der Struktur des Blogposts reduziert sich damit auf die Frage, wann wechselt der Automat seinen Zustand?

Eine Transition z.B. von “idle” zu “post” wurde so umgesetzt, dass zunächst geprüft wird, ob es sich um eine Überschrift (<h1> bis <h6> Tag) handelt und der Inhalt der Überschrift dem gesuchten Titel sehr ähnlich ist. Die Ähnlichkeit wird dabei mit der Levenshtein-Distanz gemessen. Sind die Bedingungen für die Transition erfüllt, so wechselt der Automat seinen Zustand von “idle” zu “post” und alle folgenden Knoten im Baum werden als Blogpost interpretiert. Der in Blogsatz eingesetzte Automat funktioniert in seinen Grundzügen. Hier gibt es allerdings noch einigen Entwicklungsbedarf, da der aktuell verwendete Korpus sehr klein ist. Durch das Hinzufügen von weiteren Transitionen kann das Erkennen der Blogstruktur sukzessive verbessert werden.

Die Bewertung

Die zweite Aufgabe befasst sich mit der Bewertung der Wissenschaftlichkeit von Blogposts. Dabei wird je ein englischsprachiger Blogpost und zugehörige Kommentare betrachtet und eine Relevanz im Intervall [0,1] ausgegeben. 0 steht für “gar nicht wissenschaftlich” und 1 steht für “vollkommen wissenschaftlich”.

Dazu muss man zuncähst definieren was “Wissenschaftlichkeit” bedeutet. Für den Anfang der Processor-Komponente beschränken wir uns auf die Wirtschaftswissenschaften. Dazu greifen wir auf den Standard-Thesaurus-Wirtschaft (STW) der ZBW zurück. Dieser enthält mehr als 6.000 Schlagwörter aus dem Umfeld der Wirtschaftswissenschaften. Später kann die Bewertung um weitere Thesauri ergänzt werden.

Die Umsetzung

Für die Umsetzung wird zunächst der Text mithilfe des OpenNLP Frameworks mit POS-Tags versehen. POS steht dabei für Part-of-speech und ermöglicht es so bestimmte Wortarten im Text zu erkennen. Aus dem annotierten Text wird anschließend eine Liste der im Text enthaltenen Nomengruppen generiert.

Um nun zu bestimmen, wie wissenschaftlich der Text ist, benötigen wir die Begriffe des STW. Diese Daten liegen als RDF-Tripel vor und werden ebenfalls als Liste eingelesen. Später können hier alle Thesauri, die mithilfe der SKOS Ontologie modelliert wurden, hinzugefügt werden.

Der nun folgende Listenvergleich wurde zunächst als exakter Vergleich implementiert und anschließend schrittweise verbessert. Das Problem bei dem Vergleich der Nomengruppen aus dem Text mit den Begriffen im Thesaurus ist, dass ähnliche Wörter oder Wortgruppen häufig vorkommen, aber bei einem exakten Vergleich nicht erkannt werden. Vor allem bei Plural und Singularformen gibt es Probleme.

Übersicht Architektur Blogsatz-Processor

Übersicht Architektur Blogsatz-Processor

Eine Nomengruppe im Text wie z.B. “corporate insurances” stimmt nicht exakt mit dem Singular “corporate insurance” überein. Aus diesem Grund wurde auf Stemming zurückgegriffen. Dazu werden vor dem Vergleich alle Begriffe aus dem Thesaurus auf ihren Wortstamm zurückgeführt und in die Liste aufgenommen. So wird aus dem Begriff “computer” der Wortstamm “comput”. Anschließend wird mit jedem Wortstamm eine Prefixsuche in der Liste der Nomengruppen durchgeführt. Das Verhältnis von gefundenen Begriffen zu Nomengruppen insgesamt gibt dann die Wissenschaftlichkeit des Textes an.

Diese Betrachtung stellt allerdings nur eine möglich Dimension bei der Bewertung der Wissenschaftlichkeit dar. Weiter wurden Grundbautsteine für das Zählen von Kommentaren und das Finden von Personen umgesetzt, jedoch vorerst nicht mit in die Bewertung einbezogen. Hier sind ebenfalls weitere Dimensionen wie Satzlänge, Absatzlänge oder das Verhältnis von Text zu Bild denkbar.

Und was ist mit dem Engländer?
Engländer, Bild: CC-BY-NC kefraya bei flickr.com

Engländer (Werkzeug), Bild: CC-BY-NC kefraya bei flickr.com

Der bereits im Titel erwähnte Engländer kam erst nach der Zwischenpräsentation ins Spiel. Die Organizer- und Processorkomponente wurde in Java umgesetzt und getestet. Eigentlich war die Implementierung so gut wie fertig, doch sie waren noch keineswegs Cloud-kompatibel.

Die für das Crawling eingesetzte Software Bixo baut auf dem Framework Cascading auf. Cascading stellt dabei Klassen und Interfaces zur Verfügung, die eine einfachere Programmierung auf der Cloud-Infrakstruktur Hadoop ermöglichen. Hadoop selbst ist dabei eine freie Implementierung des MapReduce Algorithmus von Google.

Hadoop verarbeitet dabei die Daten in einzelnen Jobs, die in der Cloud verteilt ausgeführt werden. Das Implementieren von Map- und Reduce-Jobs wird durch Cascading erheblich vereinfacht. Hierbei wird die Programmstruktur nicht in einzelne Jobs, sondern in Rohre (Pipes) zerlegt, die dann zu einem Netz (Flow) zusammengeschlossen werden. Die Daten werden dabei als Tupel codiert, die von Quellen (Sources) zu den

Ausgängen (Sinks) fließen. Auf dem Weg durch das Netz können die Tupel z.B. gefiltert, modifiziert, aufgespaltet und zusammengeführt werden.

Zur Laufzeit wandelt Cascading das erstellte Rohrnetz in MapReduce-Jobs um, die dann auf einer Hadoop-Infrastruktur ausgeführt werden. Die FetchPipe aus dem Bixo Projekt z.B. nimmt Tupel mit URLs entgegen und gibt Tupel mit den gecrawlten Inhalten zurück. Diese können dann im Netz weiter analysiert und bearbeitet werden.

Der Umbau

Für uns bedeutete das in erster Linie: Umbauen. Unser Programmfluss passte einfach nicht zu der Struktur, die für die Implementierung mit Pipes und Funktionen bei Cascading nötig ist. Zunächst wurden die wichtigen Kernelemente der Implementierungen extrahiert und alle nicht mehr benötigten Abhängigkeiten aus den Projekten entfernt. Anschließend erfolgte die Restrukturierung in einzelne Komponenten für Cascading.

Um die Daten bzw. die Tupel im Rohrnetz zu verändern werden bei Cascading Funktionen benutzt. Das Interface “Function” markiert eine Klasse als eine solche Funktion. Eine Funktion bekommt als Eingabe genau ein Tupel und liefert ein oder mehrere Tupel zurück. Die wesentlichen Operationen haben wir in die folgenden Funktionen gegliedert:

Organizer
  1. FeedParserFunction
    Atom- oder RSS-Feeds einlesen und URL, Titel, Author ausgeben
  2. BlogpostParserFunction
    HTML Dokumente einlesen und Blogposts und Kommentare ausgeben
  3. CleanUpFunction
    HTML Inhalt von nicht benötigten Elementen bereinigen (u.A. <form> Elemente und alle Elemente, die keinen Text beinhalten)
  4. HCardFunction
    Das Microformat HCard erkennen und die Autorinformation ausgeben (wird vor allem bei Kommentaren benötigt)
Processor
  1. SplitSentence
    Auftrennen des Textes in einzelne Sätze
  2. TokenizeSentence
    Feinere Zerlegung der Sätze in sog. Tokens (Grundbausteine der OpenNLP-Verarbeitung)
  3. FindPersons
    Erkennen von Namen (von Personen) im Text
  4. FindNoundgroups
    Zusammensetzen der Tokens zu Nomengruppen
  5. ThesaurusTrial
    Listenvergleich der Nomengruppen mit Thesaurus

Bei der Umsetzung wurde darauf Wert gelegt, auch zu jeder Funktion einen Unit-Test zu implementieren, um das Verhalten der Funktion zu überprüfen. Da die Dokumentation des Cascading-Frameworks sehr oberflächlich und gerade bei dem Thema Unit-Testing gar nicht vorhanden ist, wurden alle Erfahrungen im Comsys-Wiki notiert, so dass hier mit der Weiterentwicklung direkt angesetzt werden kann.

Ausblick

Die grobe Struktur für das Erfassen, Strukturieren und Bewerten von Blogposts wurden bereits umgesetzt. Es gibt allerdings auch an vielen Stellen noch Raum für Verbesserungen. Der nächste Schritt besteht darin, die Blogsatz-Komponenten mit einem möglichst großen Korpus an Blogposts zu testen und die Komponenten schrittweise so zu erweitern, dass die Wissenschaftlichkeit möglichst zutreffend beurteilt werden kann.

Die wesentlichen Anknüpfungspunkte sind zum einen die Transitionen des Automaten in der Organizer-Komponente und die Bewertungsdimensionen in der Processor-Komponente. Für diese Bereiche sind zwar die Ansätze gemacht, aber es gibt noch viel Raum für wissenschaftlichen Arbeiten oder Praktika bei der AG Comsys.

Comments
One Response to “Blogsatz: Mit dem Engländer in die Cloud”
  1. Norbert Luttenberger says:

    Liebe Frau Schmittke, lieber Herr Hoyer, danke für diesen hervorragenden Beitrag sowohl zu unserem Projekt als auch zu unserem Blog! Ich hoffe, auf diese Art und Weise werden wir das Projekt Blogsatz zum Erfolg bringen können!