Suchmaschine optimieren

Aus THM-Wiki
Wechseln zu: Navigation, Suche
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Team-Logo
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Team-Style "FH-CI"

Die Projekte Suchmaschine optimieren und XSRF-Schutz und Multi-Tabbing wurden im Rahmen der Diplom-/Master-Veranstaltung Methoden des Software-Entwicklungsprozesses im Wintersemester 07/08 durchgeführt. Dieses Dokument beschreibt die Aufgaben und Ergebnisse des Teams "Suchmaschine".

Im Rahmen der Veranstaltung entwarf jedes Team ein Team-Logo und einen Team-Style für eStudy. Die Styles beider Teams traten anschließend mit 14 weiteren Styles aus anderen Veranstaltungen in einem portalweiten Ranking gegeneinander an. Der Team-Suchmaschine-Style FH CI gewann das Ranking mit einer Wertung von 1.9 vor den Styles Just Pleasant und Glaucous Design.

Auftragsentwicklung

Der Kunde beauftragte das Team Suchmaschine die folgenden Punkte in einem dreiwöchigen Planspiel "Auftragsentwicklung" umzusetzen. Es stand dabei ein Budget von 30 PT zur Verfügung. Die Entwicklung fand in einem Team von sieben EntwicklerInnen statt. Meist wurden die einzelnen Themen in Zweiergruppen angegangen.

Objektorientiertes Re-Design

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Klassendiagramm (vorher)

Dieses Kapitel beschreibt das Redesign des Suchmaschinen-Quellcodes. Der Quellcode wurde zum Zwecke der Übersichtlichkeit,Wartbarkeit und Erweiterbarkeit neu strukturiert. Dazu wurden die alten Konzepte keinsfalls verworfen, sondern nur neu gekapselt. Die Strukturierung des Quellcodes ist nun vielmehr objektorientiert. Zur Lösung verschiedener Entwurfsprobleme wurde zwei verschiedene Muster gewählt, Template Method und Strategy.


Problem:

Mit dem OO – Redesign und der Modulbauweise handelt es sich um zwei verschiedene User Stories. Aufgrund der Implementierung der Suchmaschine sind diese beiden User Stories jedoch stark verwandt, da deren Eingriffsbereich sich sehr stark überschneidet.

Der wichtigste Motivationsgrund für eine OO – Redesign ist die Start – Methode der Klasse Suchmaschine. Sie ist veraltet und genügt nicht den Prinzipien der Objektorientierung. Das Haupt Makel ist jedoch die Komplexität der Methode. Diese wird an der Größe der Methode (Anzahl der Zeilen) und der Verschachtelungstiefe gemessen. Hinzu kommt das hohe Maß an Redundanz, wodurch die Start – Methode sehr schwer zu warten ist. Ein weiteres Merkmal ist die Fehleranfälligkeit bei Änderung der Methode. Da eine Änderung an vielen Stellen vollzogen werden muss, ist die Wahrscheinlichkeit dass sich Fehler einschleichen sehr hoch. Der Benutzer besitzt die Möglichkeit die Suche auf verschiedene eStudy Module auszudehnen bzw. einzuschränken. Diese Module sind fest codiert in der Start – Methode verankert was der Haupte Grund für die Größe der Methode ist. Der entscheidende Nachteil dieser Variante ist jedoch die Erweiterbarkeit der Suchmaschine. Werden neue Module in eStudy hinzugefügt, muss die Start - Methode angepasst werden um die Module in der Suchmaschine zu integrieren. Ideal wäre, wenn sich neue eStudy – Module in der Suchmaschine selbst platzieren und dem Benutzer die Wahl geben seine Suchanfrage auf diese auszudehnen. Beide User Stories sind durch die zu optimierende Start – Methode stark verwandt.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Klassendiagramm (nachher)


Ziel:

  • Modulare Erweiterung der Suchmaschine
  • Entschlackung der Start – Methode
  • Anpassung an OO – Design Prinzipien

Stemming

Stemming-Hauptklasse

Die Stemming-Hauptklasse dient dazu, ein standardisiertes Interface zum Zugriff auf die Stemming-Algorithmen anzubieten. Konkret heißt dies, dass die Klasse "class.stemming.inc.php" als Schnittstelle die Methoden "Array[][] getCapabilities()" und "Array[] run($language, $algorithm, $token)" zur Verfügung stellt. Dabei liefert die Methode "getCapabilities()" die Tupel [Sprachkürzel][Algorithmusname] der verfügbaren Sprach-Algorithmus-Kombinationen zurück, während mit "run($language, $algorithm, $token)" Sprache ($language) und Algorithmus ($algorithm) ausgewählt werden, und das auf den Wortstamm zurückzuführende Wort ($token) übergeben wird. Gemäß der Beschreibungsdatei "Algorithms.txt" im Unterverzeichnis "stemming" können beliebige Kombinationen von Algorithmen und Sprache als Klasse implementiert und so sehr einfach in das Stemming-Konzept eingebunden werden.

Der Konstruktor der Klasse durchsucht das Verzeichnis "stemming" nach Dateien mit Stemming-Algorithmen-Klassen und speichert eine Liste dieser Klassen intern. Beim Aufruf der run()-Funktion wird auf Basis des übergebenen Sprachkürzel/Algorithmusnamen-Tupels die entsprechende Stemming-Klasse ausgewählt, instanziert und deren run()-Methode ausgeführt. Neben einigen Validitätstests (z.B. ob die übergebene Sprachkürzel/Algorithmusnamen-Kombination verfügbar ist) verfügt die Hauptklasse über eine Datenbankanbindung, die als Cache verwendet wird, um die Zugriffs- bzw. Antwortzeiten zu beschleunigen. Wird die gesuchte Wort->Wortstamm-Kombination bereits in der Datenbank gefunden, wird kein Stemming-Algorithmus mehr ausgeführt, sondern das Wort->Wortstamm-Tupel und alle verfügbaren Ableitungen des Wortes in einem Array zurückgegeben.

Probleme bei der Implementation haben sowohl PHP und ezSQL als auch eStudy bereitet.

PHP ist leider in seiner Strukturierung sehr inkonsequent. So mußte z.B. mal "./Verzeichnis" und dann wieder "../Übergeordnetes_Verzeichnis/Verzeichnis" für Pfade angegeben werden, was zu viel Try&Error-Arbeit geführt hat. Die Angabe von absoluten Pfaden hätte hier schnell Abhilfe geschafft. Deshalb wäre es sinnvoll, eine globale Variable "$settings["estudyroot"] = '<absoluter Pfad zum eStudy Root>'" zu verwenden.

ezSQL bietet zwar den Vorteil der Einfachheit, damit ist aber auch der Nutzwert stark beschränkt. Da immer nur EINE SQL-Anweisung möglich ist, sind kein Transaktionen oder verkettete SQL-Anweisungen in einem Aufruf möglich. Auch Stored Functions und Procedures werden nicht unterstützt, ebenso kein UNION. Daher müssen Abfrageergebnisse immer erst in PHP verarbeitet werden, bevor eine weitere SQL-Anweisung ausgeführt werden kann, was die Performance der Datenbankanfragen erheblich verschlechtert. Offensichtlich wird deshalb bereits PEAR-DB in eStudy eingesetzt. Hier wäre ein global verfügbarer Datenbank-Handle, wie bei ezSQL, und eine ausführliche Dokumentation wünschenswert.

eStudy verwendet ein komplexes System zur Integration seiner verschiedenen Module und Teile. Dadurch entstehen aber auch viele unerwünschte Seiteneffekte, die zu Bugs führen. So hat die Erfahrung gezeigt, dass nach einem gefixten Bug recht schnell wieder neue Probleme bei der Integration von Code in eStudy auftreten.

Ein weiteres, recht fehlerträchtiges Problem, sind die Zeichensätze. Obwohl eStudy ein recht großes, komplexes System ist, gibt es keine konsequente Policy zur Handhabung von Zeichensätzen. Dadurch enstehen skurrile Seiteneffekte, wie z.B. dass eine Datenbankanfrage nach dem Wort "aßen" die Relationen von "äsen" zurückliefert. Deshalb treten bei Verwendung des datenbankbasierten Caches immer wieder Fehler im Zusammenhang mit Nicht-ASCII-Zeichen auf. Workarounds wären zeitaufwändig und sinnlos, da dieses Problem alle Bereiche von eStudy betrifft und ständige Zeichensatzkonvertierungen die Performance (z.B. DBMS) stark reduzieren würden. Daher sollte im ganzen eStudy-Projekt konsequent ein per Programmierrichtlinien definierter UNICODE-Zeichensatz verwendet werde. Hier empfiehlt sich UTF-8, da UTF-16/UCS-2 auf 65535 Zeichen beschränkt ist und UTF-32/UCS-4 vier Byte zur Darstellung von Zeichen benötigt, statt dynamisch 1 - 4 Byte, wie bei UTF-8.

Alles in allem haben die Probleme mit PHP und eStudy und die Überschätzung der Fähigkeiten von ezSQL dazu geführt, dass der PHP-Code mehrfach umgeschrieben werden mußte und Datenbankanfragen sehr träge sind.

Erschwerend kam hinzu, dass die Entwickler vor diesem Kurs keine Kenntnisse in PHP hatten und sich diese während des Projektverlaufs aneignen mußten.

Porter-Stemmer-Algorithmus

Als Stemming-Verfahren wurde der Porter-Stemmer-Algorithmus für die deutsche Sprache nach der Vorlage von www.tartarus.org umgesetzt. Der Algorithmus setzt sich aus 5 Einzelschritten zusammen (step0(),..,step4()), die der Reihe nach durchlaufen werden. Methode step0() führt vorbereitende Arbeiten durch, definiert bestimmte Bereiche, z.B. R1 (beginnt nach dem ersten Konsonanten, der einem Vokal folgt) und R2 (analog zu R1, auf den bereits definierten Bereich R1 bezogen). Die Schritte 1 bis 3 bestehen im Wesentlichen aus Ersetzungen, die ausgeführt werden nachdem bestimmte Bedingungen überprüft wurden. Methode step4() führt in Analogie zu step0() Nachbearbeitungen durch (ersetzt beispielsweise die vorhandenen Umlaute durch die entsprechenden Vokale).

Tests

Zum Stemming existieren diverse manuelle Tests als auch UnitTests, die fehlerfrei durchlaufen werden. Im Wesentlichen basieren die Tests auf dem Vergleich zwischen dem zu erwartenden Ergebnis, welches zugehörig zu einem speziellen Input aus einer Output-Datei gelesen wird, und dem tatsächlich gelieferten Ergebnis des Algorithmus.

"Meinten Sie...?"

Aufgabenbeschreibung

Das Meinten Sie...?-Feature soll der Suchmaschine eine Funktion hinzufügen, wie sie oft auf großen Suchportalen wie Google, Yahoo und anderen angeboten wird: Wenn die Benutzerin eine Suchanfrage gestartet hat, bekommt sie auf der Ergebnisseite einen alternativen Suchtext vorgeschlagen der dem ursprünglich eingegebenen ähnelt. Das neue Suchmuster ist direkt mit einer neuen Suchanfrage verlinkt und fördert eine zumeist höhere Anzahl von Fundstellen zutage. Auf diese Weise kann ein Benutzer einfach auf andere Schreibweisen des Suchbegriffes oder prägnantere Suchbegriffe hingewiesen werden.

Planung

Das neue Feature sollte einen alternativen Suchbegriff liefern und diesen, verlinkt mit einer neuen Suchanfrage auf der Ergebnisseite einfügen. Einfache Rechtschreibungsfehler sollten dabei aufgedeckt werden und bei der Eingabe eines Wortteils oder einer konjugierten oder deklinierten Form eines Suchbegriffes sollte eine Wortform angezeigt werden, die eine höhere Anzahl an Fundstellen verspricht. Die Funktion sollte möglichst isoliert von der vorhandenen Suchfunktion implementiert werden, um ihre Wartbarkeit zu erhöhen und die Ausführungsgeschwindigkeit sollte möglichst hoch sein, da sie für die Akzeptanz beim Benutzer von besonderer Bedeutung ist. Kann dabei kein Suchmuster gefunden werden, das eine höhere Quote an Fundstelle aufweist, sollte dem Benutzer kein Vorschlag für eine Alternativsuche angeboten werden.

Realisierung

Der eingebende Suchbegriff wird als Parameter der Funktion GetAlternativeText() einer Instanz der Klasse Suggestor übergeben. Für jedes Wort im Suchmuster wird anschließend eine Funktionskette durchlaufen, die jeweils die Alternative mit der höchsten Trefferrelevanz innerhalb der im eStudy indizierten Seiten zurückliefert.

Zunächst werden die Wörter gefiltert, um die Sicherheit der weiteren Ausführung zu gewährleisten. Merkmale von JavaScript, SQL und HTML sowie Sonderzeichen werden entfernt und das Ergebnis anschließend noch auf Stoppwörter wie und, aber, im und doppelte Wörter gefiltert, was der Ausführungsgeschwindigkeit zugute kommt. Danach wird ein Array mit Suchalternativen aufgebaut, die zum Schluss noch auf ihre Ähnlichkeit zum Suchbegriff hin untersucht werden und anschließend nach ihrer Trefferhäufigkeit im Suchindex von eStudy sortiert werden. Das Wort oder die Wörter mit der jeweils höchsten Trefferquote werden anschließend zurückgegeben und als Link zu einer alternativen Suchanfrage angezeigt, sofern sie sich vom ursprünglich eingegebenen Suchmuster unterscheiden.

Der Aufbau der Arrays mit den möglichen Alternativen umfasst folgende Schritte:

Phonetische Suche

Bei dieser Suchform wird nach "ähnlich klingenden" Wörtern gesucht. Dies wird erreicht, indem zwei Wörter nach bestimmten Regeln codiert werden und anschließend das Ergebnis auf Gleichheit hin untersucht wird. PHP bietet dazu die Funktion soundex(), welcher der gleichnamige Algorithmus zugrunde liegt. Da hier als Vergleichsreferenz aber der Suchindex aus der eStudy-Datenbank herangezogen werden sollte, schied ihre Anwendung aber wegen der großen Zahl von Aufrufen aus. Stattdessen wird die gleichnamige Funktion SOUNDEX() des DBMS MySql innerhalb einer Anfrage auf den Suchindex eingesetzt.

Rechtschreibungsprüfung

Als performantes Prüfwerkzeug, das neben den korrekt geschriebenen Wörtern auch noch Wortalternativen, ähnlich einem Thesaurus liefert, wird die freie Bibliothek aspell eingesetzt, welche auch in der Laufzeitumgebung von eStudy zur Verfügung steht. Wichtig: Um die korrekte Funktionsweise dieses Features zu garantieren, ist eine Neukompilierung von PHP mit pspell-Support auf dem Server notwendig.

Suche mit dem Wortstamm

Als Funktion zum Auffinden des Wortstammes, wurde der Stemming-Algorithmus eingesetzt, der von einem anderen Teil des Teams Suchmaschine optimieren entwickelt wurde. Mit dem dadurch erhaltenen Wortstamm, wird eine Fragmentsuche auf dem eStudy-Suchindex ausgeführt.

Fragmentsuche

Schließlich werden dem Alternativen-Array noch die Ergebnisse einer Fragmentsuche mit dem ursprünglichen Suchbegriff hinzugefügt, falls es sich bei dem eingegeben Muster nur um einen Teil des eigentlich gesuchten Begriffes handelt.

Anschließend werden die Alternativen mit dem Ziel gefiltert, ein recht ähnliches Wort mit der einer hohen Trefferanzahl oder das ursprüngliche Wort zurückzugeben:

Vorbereitung des Filters

Zunächst werden doppelte Begriffe entfernt, die bei der vorangegangenen Suche nach Alternativen entstanden sein können. Diese würden das Ergebnis zwar nicht verfälschen, aber die Dauer der Filterung verlängern.

Bestimmung der Wortähnlichkeit

Danach wird die Ähnlichkeit zum ursprünglichen Suchbegriff gemessen und alle Wörter unterhalb einer gewissen Schwelle verworfen. Hierzu wird der Levenshtein-Algorithmus verwendet, der Arbeitsschritte wie "hinzufügen von Buchstaben", "auslassen von Buchstaben" usw. zählt, die erforderlich sind, um ein Wort zu einem anderen zu editieren. Diese Anzahl von Arbeitschritten wird Levenshtein-Distanz genannt. Liegt sie für ein Wort im Alternativen-Array über einem vorgegebenen Wert, so wird das Wort verworfen.

Sortierung nach Treffern

Zum Schluss wird die im eStudy-Suchindex vorhandene Anzahl von Fundstellen für jedes verbleibende Wort im Alternativen-Array benutzt, um die beste Alternative zu ermitteln.:

Ergebnisse

Das Ergebnis erfüllt die in der Planungsphase ausgearbeiteten Testszenarien weitestgehend. Allerdings musste in der Version, wie sie Produktivbetrieb eingesetzt werden soll, vorerst auf den Einsatz des Stemming-Features verzichtet werden, da es die gesetzten Ansprüche an die Ausführungsgeschwindigkeit nicht erfüllen konnte.

Ausblick

Eine sinnvolle Ergänzung bei zukünftigen Weiterentwicklungen, könnte die Suche nach Alternativen für das komplette Suchmuster darstellen, wenn es sich aus mehreren Wörtern zusammensetzt. Die dazu nötige Indizierung von Wortfolgen für den Suchindex ist aber bisher nicht implementiert worden. Zur weiteren Steigerung der Geschwindigkeit, könnte schon während des Anlegens des Suchindex durch die PHP-Klasse Spider des eStudy-Projektes ein Soundex-Code oder ähnliches im Suchindex integriert werden, nach dem dann mit dem Code des Suchwortes gesucht werden kann. Außerdem könnten die Ergebnisse der PHP-Klasse Suggestor um Alternativen aus anderen Sprachen erweitert werden. Am einfachsten geht diese durch Hinzufügen weiterer Wörterbücher zur Umgebung der pspell- und der Stemming-Funktionen.

Spider-Optimierung

Vorbemerkung

Der Spider dient zur Indexierung von Dateien die nicht über die Datenbank erfasst wurden. Dazu gehören unter anderem Dateien die unter "Dateien & Links" hochgeladen wurden.

Kundenauftrag

Der Kundenauftrag bestand unter anderem in der Verbesserung der Code-Qualität und Flexibilität. Eine leichtere Erweiterung für neue Dateiformate und Dateitypen sollte möglich sein. Die Indexierung bestehender Dateiformate sollte ebenfalls verbessert werden. Dies betraf besonders Zip- und PDF-Formate.

Zu diesem Zweck wurde ein geeignetes Design-Pattern gesucht und gefunden. Das Strategy-Pattern erwies sich als geeignetes Architekturmuster.

Refactorisierung

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Code-Metriken alte Spider-Klasse

Die Umsetzung begann mit der Erstellung von Unit-Tests für die PHP-Dateien des Spiders. Die Erstellung von Skeleton-Tests ermöglichte eine objektive Erfassung der vorhandenen Code-Qualität anhand von Code-Metriken. Außerdem waren die Metriken hilfreich um die besonders refaktorisierungsbedürftigen Code-Stellen zu ermitteln.

Besonders negativ fielen die folgenden Methoden auf:

  • start (CRAP: 5945, npath: 1620)
  • searchzip (CRAP: 90, npath: 7)
  • searchpdf (CRAP: 56, npath: 18)
  • db_link_eintragen (CRAP: 56, npath: 6)
  • db_woerter_eintragen (CRAP: 42, npath: 6)
  • sinnvolles_wort (CRAP: 30, npath: 3)

Der Spider bestand aus einer einzelnen Klasse und einer Methode die von der eStudy-Automation aufgerufen wurde (z.B. beim hochladen einer neuen Datei).

Auftragsentwicklung

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Code-Metriken neue Spider-Klasse

Für die Klasse wurden möglichst vollständige Unit-Tests geschrieben. Die Code Abdeckung durch Unit-Tests reduzierte zwar die Metrik-Werte, jedoch noch nicht auf ein akzeptables Maß. Eine weitere Veränderung des Codes war damit unumgänglich.

Anhand des gewählten Design-Patterns "Strategy" wurde die Klasse Spider aufgeteilt. Die Klasse selbst ist aus Kompatiblitätsgründen erhalten geblieben und sorgt nun für den Zusammenhalt und zentralen Anlaufpunkt für die Inhaltsverarbeitung der jeweiligen Indexer.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Code-Metriken Indexer-Klasse

Die Indexer, für die Dateiformate txt, html, xml, pdf, zip, wurden aus der ursprünglichen Spider-Klasse entfernt und als IndexerStrategy implementiert. Eine lose Bindung wurde auf diese Anbindungsart erreicht. Ein Indexer kann für ein oder mehrere Dateiformate zuständig sein. Die Indexer-Zuständigkeit wird dem IndexerStrategy-Objekt von der jeweiligen konkreten Indexer-Implementation mitgeteilt. Somit ist eine flexible Erweiterung durch einfaches erstellen von weiteren Indexern möglich.

Im Zuge der Entwicklung wurden die aus der Klasse Spider extrahierten "Indexer" auf das neue Modell angepasst oder neu geschrieben. Derzeit existieren Indexer für die Dateiformate:

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Code-Metriken PluginHtm
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Code-Metriken PluginPDF
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Code-Metriken PluginVoid
  • PluginHtm: txt, htm, html, xml
  • PluginPDF: pdf
  • PluginZip: zip, sxw, stw, sxc, stc, sxi, sti, odt, ott, ods, ots, odp, odt
  • PluginVoid: alle nicht durch andere Indexer abgedeckten Dateiformate

PluginVoid nimmt eine Sonderstellung ein. Dieser Indexer gibt für alle Methoden null zurück. Der Indexer kommt zum tragen, wenn für einen konkreten Dateityp kein passender Indexer vorhanden ist. Er dient hauptsächlich dazu, dass die Methodenaufrufe immer erfolgreich sind und so viele if-Prüfungen entfallen können. Das dient nicht nur einer sauberen Code-Metrik, sondern behält auch das Design-Konzept bei.

Erstellung eines neuen Indexer

Die Implementierung eines neuen Indexers gestaltet sich dank des gewählten Design-Patterns denkbar einfach.

Die Dateibezeichnung folgt nach einer einfachen Namenskonvention class.pluginTYP.inc.php. Die so benannte Datei muss sich im Verzeichnis /suchmaschine/classes/ befinden.

Am Beispiel des Dateiformats MP3 könnte die Bezeichnung so aussehen: class.pluginmp3.inc.php. Die Klassen selbst würde dann PluginMP3 benannt und erweitert die Indexer-Klasse. Die Abstrakte Klasse Indexer implementiert das Interface Indexer. So ist sichergestellt, dass alle Plugins mindestens folgende Methoden anbieten müssen:

  • __construct()
  • open()
  • getContent()
  • close()
  • cleanup()

Unsere Beispielklasse PluginMP3 gibt im Klassen-Konstruktor den Namen an "MP3" an (dient für Logausgaben und Fehlermeldungen um ein leichtes Auffinden von problematischen Indexern zur ermöglichen). Außerdem wird im Konstruktor noch die von der Klasse unterstützten Dateiformate angeben, hier in diesem Fall "mp3".

Mittels der open()-Methode können Dateien im Filesystem geöffnet werden. Die Methode ist hilfreich, falls die Datei, wie hier, in einem Binär-Format vorliegt.

Die getContent()-Methode liefert den zu indexierenden Inhalt als String zurück. Falls die Extraktion der Daten aufwendig ist, empfiehlt sich die Inhaltsextraktion auf mehrere private Klassen-Methoden auszulagern (ein Beispiel dafür ist das PluginZip).

Das Schließen der geöffneten Datei kann über close() erfolgen. Mittels der cleanup()-Methode können erzeugte Temporäre-Dateien entfernt werden. Der IndexerStrategy sorgt für den Aufruf der Methoden.

Code-Qualität

Die Code-Qualität ist nach der Refaktorisierung und der Auftragsentwicklung messbar besser geworden.

In der aktuellen Metrik-Ansicht stehen zwar zwei Methoden mit hohen CRAP-Werten hervor, jedoch sind die Werte nur wegen der nicht 100%tigen Testabdeckung so hoch. Aus Erfahrung ist zu sagen, dass der CRAP-Faktor bei einer Test-Abdeckung >0% und <100% überzogen hoch sein kann. Der Wert ist bei genau 0% oder 100% dann deutlich niedriger. Wird der Wert vor einer Test-Abdeckung von 0% mit dem Wert bei 100% verglichen, so reduziert sich der CRAP-Wert erfahrungsgemäß um ein Drittel.

Aus diesem Grund sind die aktuellen Metriken noch nicht ganz nach dem gesteckten Ziel. Eine höhere Testabdeckung war leider nicht zu erreichen. Da aber die Lines of Code deutlich reduziert sind, ist der Einarbeitungs- und Verständnisaufwand deutlich geringer. Dies betrifft die Methoden

  • start
  • addFilesToDb

Die Metriken der beiden Methoden liegen über 20. Wie im vorherigen Absatz erläutert, ist dies jedoch aufgrund der nicht 100%igen Test-Abdeckung. Wäre hier eine 100%ige Test-Abdeckung erreicht, würde der Wert deutlich unter einem CRAP-Wert von 20 liegen.

Indexierung von MS-Office Dokumenten

Die Indexierung von MS-Office Dokumenten stellte sich mit reinen PHP-Mitteln als zu aufwendig dar.

Als Lösungsvorschlag wurde der Einsatz von Unix-Tools erarbeitet und in einer Testumgebung ausprobiert. Da jedoch in der Hetzner-Testumgebung und damit vermutlich in der Produktionsumgebung die entsprechenden Unix-Tools nicht installiert waren, wurde von einem Commit dieser Lösung abgesehen. Unter Windwos finden sich diese Tools auch nur selten installiert. Es würde für viele eStudy-Entwickler Probleme z.B. beim Datei hochladen geben.

Die Unix-Tools doc2rtf erlauben eine recht gute Transformation vom Binären-Doc-Format zu RTF bzw. zu Text. Der resultierende Text ist zwar ohne Metainformationen (z.B. Fettdruck und ähnlichem), da diese Auszeichnungen jedoch von der Suchmaschinen aktuell ohnehin nicht für ein Ranking eingesetzt werden, ist der Verlust unproblematisch.

Indexierung von PDF >v1.3

Die Indexierung von PDF Formaten >v1.3 stellte sich ebenfalls mit reinen PHP-Mitteln als zu aufwendig dar. Auch hier wurde aus den gleichen Gründen keine Lösung commited. Als Unix-Tool zur Transformation vom neueren PDF Formaten zu Text kommt pdftotext in Frage, jedoch ebenfalls mit den oben erwähnten Einschränkungen im Bereich der Metainformationen.

Wiki-Suche

Die Suchmaschine in eStudy soll die Möglichkeit bieten, Wiki-Artikel durchsuchen zu können. Eine Analyse des Problems brachte zwei Lösungsmöglichkeiten zu Tage:

  • Indizieren des Wikis und Aufbauen eines Suchkataloges in eStudy
Nachteile sind jedoch die aufwändige Neu-Indizierung bei jeder Änderung, sowie keine Möglichkeit einer Suche in Echtzeit. Neue oder geänderte Inhalte werden erst nach einer Re-Indizierung gefunden.
  • Aufrufen der Wiki-Suche durch die eStudy-Suchmaschine
Das direkte Ansprechen der Wiki-Suche bietet einige Vorteile, wie beispielsweise Finden in Echtzeit. Eine Möglichkeit dies umzusetzen ist die OpenSearch-Erweiterung für die Wiki-Software Mediawiki, auf der auch das eStudy-Wiki basiert. Diese stellt eine standardisierte XML-Schnittstelle zur Integration von Suchmaschinen dar und ermöglicht die Rückgabe von Suchergebnissen in einem maschinenlesbares Format, wie RSS oder Atom. Herausforderung dabei ist die Einbindung einer OpenSearch-Schnittstelle für eStudy. Als positiver Nebeneffekt ergibt sich der Zusatznutzen bei Bedarf weitere OpenSearch-Suchmaschinen, wie zum Beispiel Wikipedia, Britannica, Yahoo, A9 und viele andere, in eStudy integrieren zu können.

Umsetzung auf Client-Seite (eStudy)

Aufgrund der überwiegenden Vorteile wurde entschieden die Integration der nativen Wiki-Suchfunktion in die eStudy-Suchmaschine mittels OpenSearch-Schnittstelle zu realisieren. Für PHP existieren bereits zwei OpenSearch-Implementierungen:

Umsetzung auf Server-Seite (Wiki)

Auf Seite des Wikis sieht es etwas problematischer aus: Standardmäßig bietet MediaWiki OpenSearch-Unterstützung nur für das Absetzen von Suchanfragen. Das heißt, URL und Syntax der Suchfunktion werden nach außen publiziert. Die Rückgabe der Suchergebnisse erfolgt aber als gewohnte HTML-Suchergebnisseite im Wiki. Das dient in erster Linie der Browser-Integration von Suchmaschinen, wie dem Firefox-Suchfeld.

OpenSearch-Extension

Die OpenSearch-Extension für MediaWiki ermöglicht jedoch die Rückgabe von Suchergebnissen im Sinne einer vollständigen OpenSearch-Implementierung mittels Atom-Feeds. Leider ist die Projekt-Seite auf die der Download-Link verweist nicht verfügbar (Stand Januar '08). Auch ein Kontakt mit dem Entwickler brachte keinen Erfolg.

Kompromiss-Lösung

Nachdem die OpenSearch-Extension für MediaWiki nirgends zu erhalten war, wurde entschieden nur mit den in MediaWiki enthaltenen OpenSearch-Funktionalitäten zu arbeiten. Das bedeutet, Suchanfragen können über OpenSearch abgesetzt werden, die Ergebnisse kommen jedoch in Form einer HTML-Seite zurück. Diese ist dann mit Regulären Ausdrücken zu Parsen um die einzelnen Ergebnisse in einer weiterverwendbaren Form zu erhalten.

Software-Metriken im Vergleich

Zur Erfolgskontrolle des Refactorings wurde mittels der Metric-Funktion in PHPUnit von der Codebasis der Suchmaschine und des Spiders verschiedene Softwaremetriken bestimmt. Die folgende Grafik zeigt die Durchschnittswerte im Vorher/Nachher-Vergleich.


SuMa-Metriken-Vergleich.png


  • NPath
Die NPath-Metrik berechnet die möglichen Ausführungspfade durch eine Funktion. Funktionen die einen Wert über 200 haben, sollen laut Nejmeh aufgespalten werden.
  • Change Risk Analysis and Predictions (C.R.A.P.)
Die C.R.A.P. Metrik kombiniert zyklomatische Komplexität mit Überdeckungstests, die durch automatisierte Tests (Unit-Tests) realisiert wurden. Es hilft dabei Code zu identifizieren, der besonders schwer zu verstehen, zu testen oder aufrechtzuerhalten ist.
  • McCabe-Metrik, oder zyklomatische Komplexität (CCN)
Hierbei handelt es sich um eine Software-Metrik zur Bestimmung der Komplexität eines Software-Moduls. Dahinter steckt der Gedanke, dass ab einer bestimmten Komplexität das entsprechende Modul für den Menschen (sowohl die Entwickler als auch Außenstehende betreffend) nicht mehr begreifbar ist. Der zyklomatische Wert sollte für ein abgeschlossenes Modul nicht höher als 10 sein. Die Nützlichkeit ist aber umstritten: Das Einfügen normaler Anweisungen zeigt unter Umständen keinen Einfluss auf die zyklomatische Komplexität.

Lerntransfer für zukünftige Projekte

Eine abschließende Retrospektive, in Form einer Prozessanalyse zur Veranstaltung, diente dazu einen Lerntransfer für zukünftige Projekte zu ermöglichen. Dabei entstand im Team die folgende „Start-Stop-Wieder-tun“-Liste.

Was wir das nächste mal beginnen werden zu tun, ist...

  • verstärkte Team-Organisation durch die Teamleitung.
  • mehr Kommunikation im Team.
  • mehr Koordination im Team.
  • nach außen hin als eine Einheit aufzutreten.
  • klarere Ziele zu definieren.

Was wir das nächste mal nicht mehr tun werden, ist...

  • redundante Arbeit auszuführen.

Was wir das nächste mal wieder tun werden, ist...

  • regelmäßige Teamtreffen beizubehalten.
  • für ein harmonisches Klima im Team zu sorgen.
  • echte Teamarbeit - das heißt niemand profiliert sich, alle packen mit an.
  • Arbeitsteilung in 2er-Gruppen beizubehalten.


-- Bartsch-RBa -- Demming-RGD -- Lehnhardt-BLe -- Pfeifer-YPf -- Rieger-JRi -- Ryba-PRy -- Zoth-JZo