Home ORDIX AG             Dienstleistung             Trainingsshop    Kunden / Referenzen Aktuelles    Kontakt
Home  Pfeil  ORDIX News  Pfeil  3/2006  Pfeil  Java/XML
suche: 
Der Artikel richtet sich an Entwickler und Software-
Architekten, die sich für das Thema Lucene interessieren.

Glossar

Concurrent user
Benutzer, die gleichzeitig mit einer Web-Anwendung arbeiten.
DBMS
Datenbank Management System. Programme für den Umgang mit Datenbanken (z. B. Oracle, Informix, DBS).
Garbage Collection
Vorgang der Java Virtual Machine, bei dem nicht mehr benötigte Objekte zerstört werden, um ihren Speicherplatz erneut nutzen zu können.
Heap
Speicherbereich eines Programms, der vom Programm selbst verwaltet werden kann.
JCA
Java Connector Architecture. Standardisiertes Entwurfsmuster zur Einbindung von Informationssystemen in eine JEE-Umgebung.
JEE
Java Enterprise Edition. Erweiterung von Java für Server-Anwendungen.
Thread
Teilprozess eines Programms. Mehrere Teilprozesse können parallel ausgeführt werden.

Lucene unter Last beim Deutschen Rundfunkarchiv

Für Recherchen von Medien aus Rundfunk und Fernsehen verwendet das Deutsche Rundfunkarchiv Lucene als Suchmaschine. Wir zeigen die Möglichkeiten der Integration und Grenzen der Leistungsfähigkeit der Suchmaschine Lucene auf.

Das Internet zeigt, wie es geht: Suchbegriff eingeben und Suche starten. Wieso sollte also der Anwender von Individualsoftware aufwändige Eingabemasken ausfüllen? Tut es nicht auch eine Eingabezeile für den Suchbegriff? Braucht der Java-Entwickler eine Suchmaschine, so nimmt er einfach Lucene.

Braucht die Anwendung eine Suchmaschine?

Suchmaschinen werden im Internet verwendet, um Dokumente, die bestimmte Suchbegriffe enthalten, aufzufinden. Aber auch bei datenbankbasierten Anwendungen kann der Wunsch nach einer Suchmaschine aufkommen. Überall dort, wo nicht nur atomare Informationen wie etwa Name, Geburtsjahr oder Personalnummer abgespeichert werden, ist möglicherweise eine Suchmaschine von Nutzen.

In dieser Situation ist auch das Deutsche Rundfunkarchiv, das Medien aus Rundfunk und Fernsehen archiviert. Ein wesentlicher Schlüssel zu diesen Medien stellt der beschreibende Text dar. Über diesen lassen sich Medien in Zusammenhang mit Personen, Orten oder Themen finden.

So ist der Einsatz einer Suchmaschine für die Anwendungen des Deutschen Rundfunkarchivs kein Neuland: Seit Jahren wird diese Aufgabe mit Hilfe einer Großrechneranwendung erledigt.

In Zusammenhang mit der bevorstehenden Ablösung des Großrechners wurde für eine Anwendung Lucene als Suchmaschine eingesetzt. Das Projekt wurde beim Hessischen Rundfunk unter Beteiligung der ORDIX AG durchgeführt.

Technische Details der Anwendungsarchitektur

Abb. 1: Architektur der Archivanwendung.
Abb. 1: Architektur der Archivanwendung.

Die Archivanwendung zur Recherche von Bildmaterial ist als reine Web-Anwendung realisiert worden. Die eingesetzten Komponenten sind der Abbildung 1 zu entnehmen.

Tomcat wird als Web-Container verwendet. Das Struts-Framework unterstützt die Verarbeitung eingehender HTTP-Requests und die Erzeugung der Response. In dieses Framework sind die Controller- und Anzeigelogik eingebettet.

Suchanfragen werden in erster Linie an die Lucene- Komponente weitergeleitet. Diese greift auf ein Verzeichnis mit Index-Dateien zu, das in der Abbildung als Lucene-Index dargestellt ist.

Dabei wurden neben Volltextsuchen auch so genannte Filter implementiert: Das Suchergebnis wird aufgrund von Feldinhalten eingeschränkt.

Das Ergebnis der Suche sind einerseits Schlüssel für die gesuchten Medien. Darüber hinaus sind im Lucene-Index andererseits aber auch Daten zu den Medien abgelegt, die bei der Übersicht der Suchergebnisse dargestellt werden.

Detailinformationen zu einzelnen Medien werden aus der Datenbank ermittelt. Als Persistenzschicht kommt Hibernate zum Einsatz. Ein Web- Server liefert die Mediendaten. Der Zugriff wird über die Anwendung autorisiert und erfolgt über die Komponente HttpClient des Jakarta Commons-Projektes.

Eine eigenständige Anwendung, die als Komponente „Inverter“ in der Abbildung 1 auftaucht, sorgt für die Aktualität des Lucene-Index. In festgelegten Intervallen wird diese Anwendung gestartet. Sie aktualisiert den Lucene-Index anhand der protokollierten Veränderungen in der Datenbank.

Erste Erfahrungen

In der vorgestellten Archivanwendung erweist sich Lucene als zuverlässig. Sowohl parallel durchgeführte Suchen als auch die gleichzeitig ablaufende Indexierung sind unproblematisch. Die Performance ist zufriedenstellend.

Die Erfahrungen während der Entwicklung zeigten aber auch, dass Lucene in einem instabilen Umfeld problematisch sein kann:

Kommt es zu Ausnahmesituationen, so muss berücksichtigt werden, dass Lucene File Handler Betriebssystem-Ressourcen beanspruchen. Werden diese nicht freigegeben, so führt dieser Mangel zu einem zeitweiligen Stillstand der Anwendung.

Dabei ist es nicht ausreichend, dass in Zusammenhang mit der Garbage Collection die Ressourcen automatisch wieder freigegeben werden. Eine Garbage Collection findet nämlich nur dann statt, wenn die Ressource „verfügbarer Hauptspeicher“ (Heap) knapp wird.

Dann kann es aber bereits zu spät sein und die Ressource File-Handler ist aufgebraucht. Die gesamte Anwendung kommt zum Stillstand. Damit ist trotz aller Hilfestellung durch Java der Entwickler gefordert. Sorgfältig muss dieser mit den Ressourcen umgehen.

Um die weitere Entwicklung zu unterstützen, ist das nächste Ziel, die Suche mit Lucene so zu kapseln, dass eine zentrale Kontrolle über den Ressourcen-Verbrauch durchgeführt werden kann.

JCA: Gute Connections zu Managern mit Factories

Zur Kapselung des Suchdienstes wird das von Sun vorgeschlagene Architekturmodell JEE Connector Architecture eingesetzt. Diese Architektur wird von Sun empfohlen, um Dienste an einen Application Server anzubinden. Auch wenn diese Architektur nicht gerade als übersichtlich zu bezeichnen ist, gibt es doch einige überzeugende Gründe. Zunächst handelt es sich um einen Standard:

Es ist davon auszugehen, dass diese Architektur mehrfach erprobt wurde. Eine Dokumentation für die Implementierung und Verwendung ist dadurch verfügbar. Aber auch die Perspektive, die Suchfunktionalität zukünftig durch einen JEE Application Server zur Verfügung zu stellen, spricht für diesen Ansatz.

Für die Implementierung werden die Schnittstellen, die zu diesem Architekturmodell gehören, in Form des Pakets connector.jar heruntergeladen. Abbildung 2 zeigt in einem Kollaborationsdiagramm die wesentlichen Klassen im Einsatz.

Abb. 2: Kollaborationsdiagramm für den Zugriff auf eine Lucene Connection.
Abb. 2: Kollaborationsdiagramm für den Zugriff auf eine Lucene Connection. (vergrößern)

Auf den ersten Blick wimmelt es nur so von Managern und Factories. Alle haben jedoch – genau wie in einer gut organisierten Behörde – ihre abgesteckten Verantwortlichkeiten. Da ist die Schnittstelle zum JCA-Client, die ConnectionFactory. Nur über sie kommt ein Client an die begehrte Connection heran.

Die ConnectionFactory nimmt nur Anträge für die Ausgabe einer Connection über ein Antragsformular, die ConnectionSpec, entgegen. Hier trägt der Antragsteller sein Begehren ein und spezifiziert damit den Suchdienst.

Beauftragt wird dann der ConnectionManager, eine Connection zu organsieren. Dieser nimmt aber nur Formulare vom Typ ConnectionRequestInfo an. Diese werden "freundlicherweise“ von der ConnectionFactory erstellt. Der ConnectionManager prüft, ob er eine Connection aus einem Pool herausgeben kann oder ob eine neue Connection zu erstellen ist.

Der ConnectionManager ist Herr über die Ressourcen. Einerseits wird die Anzahl der herausgegebenen Connections von ihm beschränkt. Andererseits wird ihm die wichtige Aufgabe zugeteilt, zu prüfen, ob herausgegebene Connections vom Benutzer vergessen wurden. Diese werden aktiv beseitigt. Der ConnectionManager kann damit eventuell auftretende Ressourcen-Lecks stopfen.

Ein ConnectionManager wird oftmals mit dem Application Server mitgeliefert. Er kann aber auch ohne großen Aufwand selbst implementiert und dann auch auf einem Application Server eingesetzt werden.

Faktisch hält der ConnectionManager eine Liste von Connections in einem Pool vor. Muss eine neue Connection erstellt werden, so wird diese Aufgabe von einer ConnectionFactory erledigt, die eine ManagedConnection erstellt.

Der ConnectionManager wird intern informiert, wenn eine Connection freigegeben oder ungültig wird. Dazu ist der ConnectionManager direkt als ConnectionEventListener implementiert.

Bei der ausgeführten Implementierung werden Connections nur einmalig verwendet. D. h., dass sie nach ihrer Erzeugung, Verwendung und Freigabe unmittelbar zerstört werden.

Das Erstellen einer neuen Connection ist mit geringem Aufwand möglich und eine neue Connection hat unmittelbar auch Zugriff auf die aktuellsten Daten. Der Gebrauch einer Connection ist der Abbildung 3 zu entnehmen.

Abb. 3: Kollaborationsdiagramm für die Suche.
Abb. 3: Kollaborationsdiagramm für die Suche.

Zur Ausführung einer Suche fordert ein JCAClient eine Interaction von der Connection an. Über die Methode execute wird die Suche ausgeführt. Durch eine InteractionSpec und durch Records werden die Parameter zur Spezifikation der Art der Suche angegeben.

Die InteractionSpec definiert dabei die auszuführende Funktion, die übergebenen Records enthalten die erforderlichen Argumente. Das Ergebnis der Suche sind Records, im konkreten Fall als List implementiert.

Nichts als Suchen

Durch die Kapselung des Suchdienstes ist es nun möglich, die Suche allein hinsichtlich ihres Lastverhaltens zu untersuchen. Selbstverständlich hängen die konkreten Ergebnisse eines solchen Lasttests wesentlich von der eingesetzten Hardware und dem Betriebssystem ab.

Darüber hinaus wird die eingesetzte Java Virtual Machine die Ausführungsgeschwindigkeit beeinflussen.

Die Lasttests werden auf einem Entwicklungsrechner unter dem Betriebssystem Microsoft Windows XP durchgeführt.

Ziel des hier durchgeführten Lasttests ist in erster Linie, die Einflussgrößen zu ermitteln, die bei der Auslegung der Suchmaschine berücksichtigt werden müssen:

Zielgröße ist die Antwortzeit. Wie lange muss ein Benutzer auf die Suchergebnisse warten?

In einem ersten Versuch werden die Parameter „Anzahl der Treffer“ und „Komplexität der Suchanfrage“ untersucht. Dazu werden Suchanfragen gestellt, die zu einer unterschiedlichen Ergebnismenge führen (siehe Abbildung 4).

Abb. 4: Antwortzeiten der Suche bei unterschiedlichen Suchanfragen.
Abb. 4: Antwortzeiten der Suche bei unterschiedlichen Suchanfragen.

Die Versuchsreihen unterscheiden sich in diesem Fall nur durch die Suchanfragen. In der ersten Reihe wird nach einem einzelnen Suchbegriff gefragt. Durch die Variation des Suchbegriffs werden unterschiedlich viele Treffer gefunden. In diesem Fall 10, 1000 und 10000.

Auch wenn sich die Trefferzahlen um Größenordnungen unterscheiden, hat dieses keinen Einfluss auf die Antwortzeit. Diese schwankt zwischen 0,15 und 0,25 Sekunden.

Die Anzahl der Treffer stellt damit keinen Parameter dar, der die Antwortzeit beeinflusst. Auch die Komplexität der Anfrage spielt in der Regel keine Rolle.

Untersucht wurde dabei die Angabe von 2 Suchbegriffen, die logische Verknüpfung von Suchanfragen und die durch Lucene angebotene Proximity-Bedingung. Bei dieser Bedingung kann angegeben werden, wie weit zwei Suchbegriffe voneinander entfernt vorkommen müssen.

Nur die Fuzzy-Suche erhöht die Antwortzeit signifikant. Bei dieser Suche wird nach dem Suchbegriff und nach ähnlichen Begriffen gesucht. Dabei werden ähnliche Begriffe mit einem Fuzzy-Algorithmus gesucht. Diese Art der Suche führt ungefähr zu einer Verdoppelung der Antwortzeiten.

Einen unbestreitbaren Einfluss auf die Antwortzeit hat die Anzahl der parallel durchgeführten Suchen. Dadurch, dass bei der Implementierung des Suchdienstes für jede Suche neue Ressourcen verwendet werden, ist nicht zu erwarten, dass parallele Suchen zu einer Verringerung der Antwortzeit führen.

Im günstigsten Fall kann mit einem linearen Verlauf der Antwortzeit gerechnet werden: Doppelt so viele parallele Suchanfragen führen zu einer doppelt so langen Antwortzeit für jede einzelne Suchanfrage. Die Antwortzeiten (siehe Abbildung 5) kommen diesem Idealverhalten sehr nahe.

Abb. 5: Antwortzeiten der Suche bei parallelen Suchanfragen.
Abb. 5: Antwortzeiten der Suche bei parallelen Suchanfragen.

In der Untersuchung wird die Anzahl der gleichzeitigen Suchanfragen von 1 bis 50 variiert. Aufgetragen sind einerseits die Mittelwerte und die zugehörige Standardabweichung. Zusätzlich sind die Maximalwerte angegeben.

Dem Diagramm ist zu entnehmen, dass die Antwortzeiten leicht überproportional ansteigen. Die Ursachen für diesen Anstieg lassen sich möglicherweise durch den Verwaltungsaufwand der Threads erklären. Auffällig ist das Verhalten bei 30 parallelen Suchanfragen. Hier kommt es zu einem erheblichen Anstieg der Antwortzeiten. Dieser Anstieg ist auf das Speichermanagement der Virtuellen Maschine zurückzuführen.

Hier findet parallel zur Suche mit großer Sicherheit eine Garbage Collection statt. Für die weiteren Versuche musste der verfügbare Hauptspeicher vergrößert werden. Als letzter Parameter wird die Anzahl der zu durchsuchenden Dokumente von 30.000 auf 10.000 reduziert. Die Abbildung 6 zeigt, dass dieser Parameter einen erheblichen Einfluss auf die Antwortzeiten hat.

Abb. 6: Einfluss der Dokumentenanzahl.
Abb. 6: Einfluss der Dokumentenanzahl.

Die Abbildung verdeutlicht, dass sich ausgehend von einem linearen Verhalten pro Dokument die Antwortzeit um 0,002 Millisekunden verlängert. Dieser Wert wirkt zunächst einmal klein. Muss jedoch davon ausgegangen werden, dass die Anzahl der Dokumente vielleicht die Millionengrenze überschreitet, so wird die Antwortzeit

Fazit

Die Lasttests bestätigen zunächst den ersten Eindruck, dass Lucene eine zuverlässige und robuste Suchmaschine ist. Die Kapselung von Lucene in eine Java-Connector-Architektur vereinfacht den programmiertechnischen Umgang mit der Suchmaschine.

Die Ergebnisse zeigen, dass für den gegebenen Anwendungsfall die Antwortzeiten ausreichend sind. Zur Einordnung der Ergebnisse ist zu berücksichtigen, dass 50 gleichzeitige Suchprozesse in der Realität durch ungefähr 200 Benutzer (concurrent user) verursacht werden.

Dennoch dürfen die wesentlichen Parameter, die Einfluss auf die Antwortzeiten nehmen, nicht vernachlässigt werden: „Anzahl der parallelen Suchprozesse“ und „Anzahl der Dokumente“. Beide Parameter gehen linear in die Berechnung der Antwortzeiten ein.

Für Anwendungen mit einer großen Datenmenge (einige 100.000 Datensätze) oder mit einer sehr großen Zahl an Benutzern sind die Grenzen durch die Geduld der Benutzer definiert. Um den Einsatzbereich von Lucene zu erweitern, sollten neben der Universalstrategie, leistungsfähigere Hardware einzusetzen, noch die folgenden Strategien geprüft werden:

Durch eine Verteilung der Last auf mehrere Web-Container, die jeweils ihren eigenen Index haben, skaliert die Antwortzeit mit der Anzahl der Web-Container-Instanzen.

Bei Unix/Linux-Servern steht die Möglichkeit zur Verfügung, den Index auf ein RAM-basiertes Dateisystem zu legen. Damit kann die Ausführungszeit erheblich beschleunigt werden. Der Lucene-Index kann auch in einer Datenbank abgelegt werden. Hierdurch ist ein Vorteil durch Caching-Mechanismen des DBMS zu erwarten.

Braucht auch Ihre Anwendung eine Volltextfunktionalität? ORDIX berät Sie gern.

Dr. Stefan Koch (info@ordix.de).