• Keine Ergebnisse gefunden

Prospector-Algorithmus

6.3 Integration von Prospector in Carrot 2

6.3.1 Prospector-Algorithmus

Im ersten Schritt sollte der Prospector-Algorithmus als ein Clustering-Algorithmus f¨ur Carrot2 adaptiert werden. Da dessen Web-Oberfl¨ache nicht zwischen den einzelnen Benutzern unter-scheiden kann, wurden f¨ur die Entwicklung mit dem urspr¨unglichen Prospector-System ein Benutzer und entsprechende Modelle erzeugt und diese fix im Algorithmus definiert. Dies hatte auch den Vorteil, dass sich die Parameter des Algorithmus nicht ¨anderten, und so beim Testen korrekte Ergebnisse ohne viel M¨uhe erkannt werden konnten.

Das Carrot2 Framework basiert auf der Architektur desschrittweisen Verarbeitens von Daten und unterst¨utzt ein Austauschen der einzelnen Verarbeitungskomponenten. Da Prospector flexibel mit unterschiedlichen Datenquellen arbeiten k¨onnen soll, wurde der Algorithmus in drei unabh¨angige Schritte zerlegt:

1. Ergebnisse klassifizieren: entsprechend der Ontologie wird jedes Ergebnis klassifiziert und so in die Struktur, die den Overlay-Modellen zugrunde liegt, eingeordnet.

Prospector

Abbildung 6.4:Carrot2-Verarbeitungskette mit den Komponenten von Prospector

ODPClassifierLocal

Abbildung 6.5:Carrot2 Filter-Komponenten der Verarbeitungskette f¨ur Prospector

2. Relevanzen berechnen: mit den Informationen aus den Modellen wird f¨ur das klassifizier-te Ergebnis die vorhergesagklassifizier-te Relevanz, dass dieses den Benutzer inklassifizier-teressiert, berechnet.

3. Umreihen: die Ergebnisse werden nach absteigender Relevanz umgereiht.

Jeder dieser Schritte l¨asst sich in eine Komponente fassen und wird somit austauschbar.

Die verwendete Ontologie, die Art wie die Relevanzen berechnet werden, und deren Einfluss auf die Reihung lassen sich damit auswechseln. Konkret implementiert wurden die Schritte in den KlassenODPClassifierLocalFilterComponent,ProspectorLocalFilterComponent undScoreSorterLocalFilterComponent, die in Abbildung 6.4 in der Carrot2-Architektur ge-zeigt und Abbildung 6.5 in einem UML-Klassendiagramm zu Teilen des Frameworks in Bezie-hung gesetzt werden. Sie alle leiten sich von der Basisimplementierung einer Filterkomponente ab. Jene Komponenten, die Dokumente als Eingabe nehmen, implementieren RawDocuments-Consumer. Liefern sie Dokumente als Ausgabe, so implementieren sieRawDocumentsConsumer.

Alle drei Komponenten, sowie auch die bisher nicht genannte ODPClustererLocalFilter-Component, werden im Folgenden kurz beschrieben.

ODPClassifierLocalFilterComponent

Als Eingabe erh¨alt diese Komponente ¨uber die Methode addDocument(RawDocument doc) Daten vom Typ RawDocument. Anhand der URL des jeweiligen Dokuments wird dieses in der Ontologie des ODP klassifiziert. Ergebnis davon ist eine Liste mit den Namen jener Themengebieten, die den Pfad von der Wurzel bis zu jenem Thema, in dem das Dokument schlussendlich klassifiziert ist, bilden.

Wenn die Klassifizierung erfolgreich war, so muss diese Information zu dem Dokument-Objekt hinzugef¨ugt werden. Das InterfaceRawDocumentsieht dazu die MethodesetProperty(String propertyName, Object value)vor, mit der Name-Wert-Paare gespeichert werden k¨onnen.

Damit auch von anderen Komponenten aus sicher auf die Liste der Themengebiete zugegriffen werden kann, wird der Wert der in der Hilfsklasse ProspectorHelper definierten Konstan-teDOCUMENT_ODP_CLASSIFICATIONS als Name verwendet. Anschließend wird das Dokument

¨

uber dieaddDocument()-Methode an die nachfolgende Komponente weitergegeben.

ProspectorLocalFilterComponent

Diese Komponente ¨ubernimmt die klassifizierten Dokumente und berechnet f¨ur jedes die Re-levanz im Bezug auf das Benutzermodell und die Gruppenmodelle. Zu diesem Zweck greift es auf die schon bestehende Implementierung des Prospector-Algorithmus zur¨uck. Zuvor muss jedoch noch dasRawDocument-Objekt in das intern in Prospector verwendete Ergebnisobjekt SearchResultItemumgewandelt werden. Dieses stammt noch aus den vorangeganenen Ver-sionen, doch seine Verwendung sichert auch die Unabh¨angigkeit des eigentlichen Algorithmus von Carrot2.

Zum Umwandeln wurde die Methode getSearchResultItem(RawDocument doc, int in-dex)inProspectorHelpergeschaffen. Sie gibt ein entsprechendesSearchResultItem-Objekt zur¨uck. Intern wird dazu eine neu erstellte Unterklasse GenericSearchResultItem verwen-det. Diese verf¨ugt ¨uber die M¨oglichkeit, beliebige Name-Wert-Paare zu speichern und kann so auch Daten imRawDocument-Objekt, die noch nicht inSearchResultItemvorgesehen waren,

¨

ubernehmen. Nach dem Berechnen der Relevanz und dem Abspeichern im Ergebnisobjekt wird dieses durch getRawDocument(SearchResultItem item) wieder in ein RawDocument umgewandelt, welches anschließend an die n¨achste Komponente weitergegeben wird.

ScoreSorterLocalFilterComponent

Urspr¨unglich wurde das Umreihen der Ergebnisse ebenfalls durch den Prospector-Algorithmus erledigt. Es erschien aber als einheitlicher, das Konzept der klaren Aufteilung der einzelnen Schritte in eigenst¨andige Komponenten auch hier anzuwenden. Somit ist es m¨oglich, alterna-tive Algorithmen zum Umreihen auf Basis der Relevanzen zu finden. Wie weiter unten noch beschrieben wird, kam es im Lauf der Entwicklung tats¨achlich zu einer derartigen ¨Anderung.

Die Implementierung dieser Komponente unterscheidet sich von den bisher beschriebenen, da nicht wie beim Klassifizieren oder Berechnen der Relevanz jedes Dokument einzeln bear-beitet werden kann. Zum Umreihen wird die gesamte Liste von Ergebnissen ben¨otigt. Aus diesem Grund wird instartProcessing(RequestContext requestContext)eine leere Liste angelegt, zu der bei jedem Aufruf von addDocument(RawDocument doc) das entsprechende Dokument hinzugef¨ugt wird. Wenn von der vorangegangenen KomponenteendProcessing() aufgerufen wird, so signalisiert sie damit, dass keine weiteren Dokumente mehr kommen. In dieser Methode findet dann das eigentliche Umreihen statt.

Zu diesem Zweck wird, wie in Code 6.1 gezeigt, die in der Java-Bibliothek standardm¨aßig vor-handene, statische Methode Collections.sort(List l, Comparator c) verwendet. Diese sortiert die ¨ubergebene Liste anhand der Ordnungsrelation, die durch den Comparator defi-niert wird. In diesem Fall wird ein vonComparator abgeleitete anonyme Klasse erzeugt und die Methode compare(Object o1, Object o2)entsprechend implementiert. Die eigentliche Berechnung der Ordnungsbeziehung zwischen den zwei Objekten (0 wenn beide gleich sind, negativer Integer-Wert wenno1 kleiner und positiver wenno1gr¨oßer also2ist) wird mit den Relevanzen (im Falle von Carrot2

”score“ genannt) an die entsprechende Vergleichsfunktion der KlasseFloat delegiert.

Collections.sort(List l, Comparator c) f¨uhrt eine stabile Sortierung durch. Das heißt, dass Listenelemente mit gleicher Wertigkeit (d. h. gleicher Relevanz) ihre urspr¨ungliche Rei-hung zueinander nicht verlieren. Da die Dokument so die Verarbeitungskette durchlaufen, wie sie von der Quell-Suchmaschine zur¨uckgegeben wurden, sorgt dies bei gleichen Relevanzen

au-tomatisch daf¨ur, dass diese originale Reihung ber¨ucksichtigt wird. Dies ist insofern relevant, wenn Ergebnisse nicht klassifiziert werden konnten. In diesem Fall erhielten sie die neutrale Relevanz 0,5. All derartigen Ergebnisse bleiben in ihrer urspr¨unglichen Reihung. Nachdem die Liste sortiert wurde, muss in einer abschließenden Schleife noch jedes Dokument einzeln an die nachfolgende Komponente weitergegeben werden.

ODPClustererLocalFilterComponent

Diese Komponente erzeugt jene Struktur, die in der Web-Oberfl¨ache als Cluster-Hierarchie dargestellt wird. Diese enth¨alt die einzelnen Cluster und Untercluster sowie die Verweise auf die darin enthaltenen Dokumente. Verwendet werden dazuRawClusterBase-Objekte, die das bereits besprochene RawCluster-Interface implementieren. Beim Start der Verarbeitung in startProcessing(RequestContext requestContext) werden ein Wurzel-Cluster und ein Rest-Cluster erzeugt. Ersterer sammelt zur leichteren Handhabung alle Cluster oberster Ebe-ne (entspricht ODP-Themengebieten oberster EbeEbe-ne) als Untercluster.

...

Li st c l a s s i f i c a t i o n P a t h = ( L ist ) doc . g e t P r o p e r t y (

P r o s p e c t o r H e l p e r . D O C U M E N T _ O D P _ C L A S S I F I C A T I O N S ) ; if ( c l a s s i f i c a t i o n P a t h != null && ! c l a s s i f i c a t i o n P a t h . i s E m p t y () ) {

S t r i n g t o p i c P a t h = " ";

R a w C l u s t e r B a s e p a r e n t C l u s t e r = r o o t C l u s t e r ;

for (int i = 0; i < c l a s s i f i c a t i o n P a t h . si ze () ; i ++) { S t r i n g t o p i c = ( S t r i n g ) c l a s s i f i c a t i o n P a t h . get ( i ) ;

// Don ’ t i n s e r t e m p t y a n c e s t o r s ( if doc is in top - l e v e l t o p i c ) if ( t o p i c . l e n g t h () > 0) {

t o p i c P a t h = t o p i c P a t h + " / " + t o p i c ;

R a w C l u s t e r B a s e c l u s t e r = ( R a w C l u s t e r B a s e ) map . get ( t o p i c P a t h ) ; // If not in map we ha ve to c r e a t e a new c l u s t e r

if ( c l u s t e r == nu ll) {

c l u s t e r = new R a w C l u s t e r B a s e () ; c l u s t e r . a d d L a b e l ( t o p i c ) ;

p a r e n t C l u s t e r . a d d S u b c l u s t e r ( c l u s t e r ) ; map . put ( t o p i c P a t h , c l u s t e r ) ;

}

p a r e n t C l u s t e r = c l u s t e r ; }

}

p a r e n t C l u s t e r . a d d D o c u m e n t ( doc ) ; }

Code 6.2:Erstellen der Cluster-Hierarchie f¨ur die Klassifizierung eines Dokuments

Der Rest-Cluster enth¨alt alle Dokumente, die nicht klassifiziert werden konnten. Er wird dem Wurzel-Cluster als Untercluster hinzugef¨ugt. Ebenfalls angelegt wird eine Abbildung (Map) zwischen Themengebiet-Pfaden (z. B.

”Computers/Programming/Languages/Java“) und dem entsprechenden Cluster am Ende dieses Pfades. Dies erspart das Durchlaufen des Baumes, um den richtigen Cluster f¨ur ein klassifiziertes Dokument zu finden.

In addDocument(RawDocument doc) wird zuerst das Dokument unver¨andert an die nachfol-gende Komponente weitergegeben. Anschließend wird dessen gespeicherte Klassifizierung ge-laden (siehe Code 6.2 auf der vorherigen Seite). Es handelt sich um eine geordnete Liste von Themennamen, die im ODP-Datenbestand den Pfad zum eigentlichen Thema des Dokuments angeben. Dieser Pfad wird durchlaufen und f¨ur jede Ebene versucht, mit der Abildung das entsprechende Cluster-Objekt zu erhalten. Dieses wird immer als aktueller Eltern-Cluster in einer Variable gehalten. Sollte die Abbildung kein Cluster-Objekt finden, so wird ein neues mit dem Namen des aktuellen Themas erzeugt, als Untercluster des Eltern-Clusters gespeichert und als neuer Eltern-Cluster verwendet.

Nach dem vollst¨andigen Durchlaufen des Klassifizierungspfades entspricht der Eltern-Cluster jenem Thema, in welches das Dokument im ODP klassifiziert wurde. Diesem Cluster wird es dann zugeordnet. Beim Beenden der Verarbeitung inendProcessing()werden schließlich alle Cluster oberster Ebene (also auch der Rest-Cluster) einzeln mitaddCluster(cluster) an die nachfolgende Komponente weitergegeben.

Einbindung der Komponenten

Um Prospector in Carrot2 verwenden zu k¨onnen, m¨ussen die Komponenten konfiguriert und zu einem Algorithmus/Prozess verbunden werden. Im Verzeichnisweb/algorithmsder Web-Anwendung wurden daher entsprechende BeanShell-Skripte angelegt. Als Beispiel sei die De-finition der Prospector-Filterkomponente in Code 6.3 gegeben.

i m p o r t org . c a r r o t 2 . f i l t e r . p r o s p e c t o r .*;

i m p o r t org . c a r r o t 2 . cor e .*;

i m p o r t org . c a r r o t 2 . cor e . c o n t r o l l e r .*;

f a c t o r y = new L o c a l C o m p o n e n t F a c t o r y () { p u b l i c L o c a l C o m p o n e n t g e t I n s t a n c e () {

r e t u r n new P r o s p e c t o r L o c a l F i l t e r C o m p o n e n t () ; }

p u b l i c S t r i n g g e t N a m e () { r e t u r n " P r o s p e c t o r "; } };

// R e t u r n the ID of the c o m p o n e n t and its f a c t o r y .

r e t u r n new L o a d e d C o m p o n e n t F a c t o r y (" filter - p r o s p e c t o r ", f a c t o r y ) ; Code 6.3: Definition der Prospector-Filterkomponente infilter-prospector.bsh

Die Verbindung der Eingabe-, Filter- und Ausgabekomponenten zur Verarbeitungskette des Prospector-Prozesses (in der Web-Oberfl¨ache als Algorithmus bezeichnet) erfolgt in einer XML-Datei im selben Verzeichnis (siehe Code 6.4). Sofern alle ben¨otigten Klassen im Java-Klassenpfad zu finden sind, l¨adt durch diese Definitionen die Carrot2 Web-Anwendung beim Start des Servlet-Containers automatisch Prospector als Standard-Algorithmus.

< ?xml v e r s i o n=" 1.0 " e n c o d i n g =" UTF -8 " ? >

< local - p r o c e s s id =" P r o s p e c t o r ">

< n ame > P r o s p e c t o r < / n ame >

< d e s c r i p t i o n > P r o s p e c t o r P e r s o n a l i z e d S e a r c h A l g o r i t h m < / d e s c r i p t i o n >

< i n p u t c o m p o n e n t - key =" input - demo - w e b a p p " / >

< f i l t e r c o m p o n e n t - key =" filter - o d p c a t e g o r i z e r " / >

< f i l t e r c o m p o n e n t - key =" filter - p r o s p e c t o r " / >

< f i l t e r c o m p o n e n t - key =" filter - s c o r e s o r t e r " / >

< f i l t e r c o m p o n e n t - key =" filter - o d p c l u s t e r e r " / >

< o u t p u t c o m p o n e n t - key =" output - demo - w e b a p p " / >

< a t t r i b u t e key =" p r o c e s s . d e f a u l t " v a l u e =" tr ue " / >

< / local - p r o c e s s >

Code 6.4: Definition des Prospector-Prozesses inalg-prospector.xml

Wie bereits erw¨ahnt, werden die Ergebnisse nur f¨ur die Anzeige der Cluster-Hierarchie durch diese geleitet, nicht jedoch f¨ur die Anzeige der Dokument-Liste. Da Prospector aber nicht wie die urspr¨unglichen Algorithmen nur Cluster erzeugt, sondern auch die Reihung der Er-gebnisse ver¨andert, musste imQueryProcessorServletvor dem Serialisieren der Dokumente Code (vom Teil f¨ur Cluster-Anfragen) zum Ben¨utzen der Verarbeitungskette eingef¨ugt werden.

Wie der dadurch entstehende Overhead (Umreihen bei Cluster-Anfragen bzw. Clustern bei Dokument-Anfragen) gemindert werden konnte, wird in Unterabschnitt 6.6.1 beschrieben.