Apache Solr unter der Lupe

Solr für Einsteiger

Isabel Drost

Apache Solr, ein Unterprojekt des Apache-Lucene-Projekts, erweitert den Suchindex Lucene Java um wichtige Funktionen: Die Anbindung an verschiedenste Projekte wird über eine HTTP/XML-Schnittstelle, die Definition des Index selbst über die Definition eines Schemas erleichtert. Außerdem unterstützt Solr viele Features, die nativ in Lucene nicht zur Verfügung stehen. So kann beispielsweise die Facettierung der Suchergebnisse die Navigation in ihn um einiges erleichtern. Der Artikel gibt eine Einführung zu Solr und einen Überblick über wichtige Solr-Features, zeigt an einem Beispiel, wie in wenigen Minuten ein eigener Suchserver aufgesetzt werden kann.

Hören Nutzer das Wort Suchmaschine, denken viele üblicherweise zuerst an Google, Yahoo oder vielleicht Bing. Neben diesen allgemeinen Portalen verwenden Internetnutzer aber tagtäglich viele weitere Suchlösungen: Von der vertikalen Suchmaschine nach Mietangeboten über Jobsuchmaschinen bis hin zu spezifischen Applikationen, die lediglich die Inhalte einer Webpräsenz durchsuchen.

Dieser Artikel soll ein Apache-Projekt vorstellen, dessen Ziel es ist, eine auf freier Software basierende vertikale Suchmaschine zur Verfügung zu stellen: Apache Solr ist ein Unterprojekt von Lucene mit dem Ziel, einen voll einsatzfähigen, möglichst leicht zu integrierenden Suchserver zur Verfügung zu stellen. Nach einer kurzen Vorstellung der Ziele des Projekts Solr wird der Artikel die besonderen Features des Suchservers vorstellen. Abschließend wird der Artikel in einem kurzen Tutorial zeigen, wie schnell und einfach mit Solr eine Suchmaschine in die eigene Webpräsenz integriert werden kann.

Mit Apache Lucene Java steht eine Java-Bibliothek zur Verfügung, die einen performanten Index für Volltextsuchen implementiert. Allerdings handelt es sich bei Lucene lediglich um eine Java-Bibliothek, die vor der Verwendung erst mehr oder weniger aufwändig in die eigene Infrastruktur eingebunden werden muss. Bei dieser Integrationsarbeit fallen einige Aufgaben wiederholt an, die in Lucene nicht automatisiert sind:

  • Vor der Indexierung durchlaufen Dokumente eine ganze Kette von Analyseschritten: Die Texte müssen aus unterschiedlichsten Dokumentenformaten extrahiert werden, Worte werden identifiziert und gegebenenfalls auf ihren Wortstamm zurückgeführt. Die Definition solcher Pipelines erfolgt in Solr über eine einfache XML-Konfiguration.
  • Es muss eine Schnittstelle implementiert werden, über die Dokumente zum Indexer gelangen. In Lucene ist dazu die Entwicklung von eigenem Code notwendig, Solr bietet mit einer HTTP/XML-Schnittstelle eine einfach zu integrierende Lösung.
  • Ein vor allem für vertikale Suchmaschinen oft gebrauchtes Feature ist die Facetierung von Suchergebnissen: Treffer sollen kategorisiert im Index abgelegt werden. Zum Suchzeitpunkt soll es möglich sein, die Trefferliste auf eine oder mehrere dieser Kategorien einzuschränken.
  • Steigen die Zugriffsraten auf das eigene Webangebot, ist es oft schnell notwendig, Suchserver horizontal zu skalieren. Es empfiehlt sich außerdem, Indexe im Backend aufzubauen und im Anschluss auf die Frontends zu replizieren. Solr bietet dazu bereits das für die üblichen Setups notwendige Tooling.
Der Lucene-Familienstammbaum
Lucene begann vor über 10 Jahren als Projekt von Doug Cutting. Ziel war die Entwicklung einer Java-Bibliothek, die einen Suchmaschinenindex implementiert. Seit dieser Zeit ist das Projekt deutlich gewachsen, hat diverse Unterprojekte generiert ¬ einige davon sind in der Zwischenzeit selbst zu eigenständigen Apache-Projekten geworden: Neben Lucene Java ¬ dem Suchmaschinenindex ¬ exisitiert mit Solr die Implementierung eines kompletten Enterprise Search Servers. Solr eignet sich insbesondere für die Implementierung von vertikalen Suchmaschinen. Mit nutchexistiert daneben die Implementierung einer allgemeineren General-Purpose-Suchmaschine: Augestattet mit einem eigenen Crawler, einem Webinterface und diversen Administrationstools erlaubt nutch die Implementierung eines eigenen Suchangebots. Aus nutch wurde die Idee der verteilten Datenverarbeitung geboren ¬ die ersten Implementierungen eines verteilten Dateisystems und einer verteilten Datenanalyse, die in nutch begannen, wurde innerhalb weniger Jahre das erfolgreiche Projekt Apache Hadoop.
Daneben existiert mit Tika eine Bibliothek zur Extraktion von Texten aus verschiedensten Dokumentformaten, beispielsweise Microsoft doc, ooxml, html etc.Mahout ist ein Projekt, dass sich auf die Implementierung skalierbarer Machine Learning Algorithmen ¬ insbesondere aus den Bereichen Text Mining und Collaborative Filtering ¬ spezialisiert hat. Mit Droids wird ein modulares Crawling-Framework entwickelt. Noch im Incubator befindlich, aber ebenfalls von Lucene-Entwicklern unterstützt, wird mit Lucene Connectors ein Framework entwickelt, das die Anbindung von Lucene an verschiedenste Content-Management-Systeme und Kollaborationsplattformen ermöglicht. Daneben existieren mit PyLucene, Lucy, Lucene.Net Ports von Lucene in verschiedenste Programmiersprachen.
Das Projekt OpenRelevance letztlich widmet sich der Vergleichbarkeit von Suchmaschinen-Benchmarks: Oft scheitert der Vergleich von Benchmarks an der Verfügbarkeit freier Datensätze. Das Ziel von OpenRelevance ist die Sammlung frei weiterverteilbarer Daten, die auch von anderen Suchmaschinenprojekten genutzt werden können, um die Qualität der implementierten Ranking-Funktion überprüfen zu können. Bisher existieren solche Datensätze hauptsächlich im Forschungskontext. Einer der bekanntesten Vertreter ist Trec. Für Open-Source-Projekte eignen sich diese Datensätze aufgrund restriktiver Lizenzbestimmungen nur begrenzt. OpenRelevance soll hier Abhilfe schaffen.

[ header = Seite 2: Solr-Features ]

Solr-Features

Solr integriert Lucene und erweitert die Bibliothek zu einem vollständigen Entreprise Search Server. Im Gegensatz zu Lucene kann Solr direkt in einem Servlet-Container ausgerollt und gestartet werden. Indexierung und Abfrage von Dokumenten erfolgen über eine HTTP/XML-Schnittstelle. Aber auch Alternativen wie JSON werden unterstützt. Mittels VelocityResponseWriter ist es letztlich möglich, ein prototypisches Suchwebinterface sehr schnell zu erstellen. Der Server kommt mit einem umfangreichen Administrationsinterface, das die Analyse der indexierten Dokumente, der getroffenen Einstellungen und der möglichen Queries vereinfacht (Abb. 1).

Abb. 1: Admin-Interface

Aufgrund seiner Architektur ist Solr hochskalierbar: Einerseits profitiert die Implementierung natürlich von einer vertikalen Skalierung hin zu mehr Rechenkapazität auf einem einzelnen Knoten. Andererseits ist es beispielsweise bei erhöhtem Query-Aufkommen leicht möglich, auch horizontal auf mehrere Rechner zu skalieren. Zusätzlich zu den in Lucene eingebauten Caches bringt Solr Higher Level Caches mit, die vor allem komplexe Suchanfragen, die wiederholt gestellt werden, beschleunigen. Die Konfiguration von Solr erfolgt hauptsächlich über XML-Konfigurationsdateien: Sowohl die Formatierung der Suchergebnisse lässt sich anpassen als auch der interne Aufbau des Index sowie die beim Indexieren verwendeten Analyzer. Auf diese Weise ist es möglich, auch ohne viel Implementierungsaufwand schnell einen Suchserver zu erstellen und ihn bei Bedarf an neue Anforderungen anzupassen.

Erste Schritte

Um erste Erfahrungen mit Solr zu sammeln, bietet sich die Verwendung des mit der Distribution mitgelieferte Beispielprojekt an: Dazu ist auf http://lucene.apache.org/solr unter RESOURCES | DOWNLOAD das letzte Release von Solr (zum Zeitpunkt des Artikels war das Version 1.4.0) herunterzuladen und auszupacken. Im Anschluss kann das im Verzeichnis example befindliche Jar einfach gestartet werden. Das mitgelieferte Beispiel nutzt jetty als Servlet-Container. Solr läuft aber ebenso gut in anderen Containern wie beispielsweise Tomcat, der auf Produktionsservern üblicher sind. Nach diesen wenigen Schritten ist der Nutzer bereits in der Lage, einen ersten Blick auf das Admin-Interface von Solr zu werfen. Dazu einfach den URL http://localhost:8983/solr/admin/ in einem beliebigen Browser aufrufen. Neben dem üblichen Query-Formular finden sich im GUI auch Links zu internen Informationen des Servers: zur aktuell verwendeten Konfiguration, zu Statistiken über die indexierten Dokumente, zu den Logging-Einstellungen (Abb. 2).

Abb. 2: Interne Informationen des Servers

Der so gestartete Index ist noch leer ¬ das heißt, es wurden bisher noch keine Dokumente indexiert. Dokumente werden über eine HTTP/XML-Schnittstelle per POST Request an Solr geschickt. Dokumente, die indexiert werden sollen, werden in einem standardisierten XML-Format an Solr geschickt (Listing 1).

<add><doc>
<field name="typ">Kaffee</field>
<field name="name">Frappucino</field>
<field name="beschreibung">Nur die besten Bohnen entfalten ein reichhaltiges Aroma. Köstlicher Kaffee und Zuckerersatzstoffe (Suessstoffe) machen ihn lecker und leicht. Moccha oder Caramel? Gemischt mit buttersüßem Karamell- oder intensivem Schokoladen-Sirup.</field>
<field name="preis">3.50</field>
</doc></add>

Das Löschen von Dokumenten erfolgt über die gleiche Schnittstelle. Es ist möglich, einerseits Dokumente basierend auf ihrer ID im Index zu löschen. Andererseits ist es auch möglich, all jene Dokumente zu löschen, die für eine vorgegebene Query zurückgeliefert werden.

<delete><id>LKI9JL9</id></delete>
<delete><query>name:Starbucks</query></delete>

Abfragen können über HTTP-Get-Requests an den Server gestellt werden. Um im obigen Beispiel eine Liste aller Kaffees, die mit Karamell-Aroma erhältlich sind nach Preis absteigend sortiert abzufragen kann folgende Query verwendet werden: http://localhost:8983/solr/select?q=karamell&sort=preis+desc. Die Antwort wird im Standardfall XML-formatiert zurückgegeben.

In Solr können Queries auch auf konkrete Felder eingeschränkt werden ¬ dann wird nicht der gesamte Dokumenttext durchsucht, sondern lediglich das ausgewählte Feld. In unserem Beispiel könnte so eine Query gestaltet werden, die lediglich alle Getränke vom Typ „Kaffee“ zurückliefert, nicht aber jene, die zufällig das Wort „Kaffee“ in der Beschreibung erwähnen. Eine entsprechende Query, die die Ergebnisse wiederum nach Preis absteigend sortiert, würde folgendermaßen aussehen: http://localhost:8983/solr/select?q=typ:Kaffee&sort=preis+desc

Nutzer einer Suchmaschine sind daran gewöhnt, pro Treffer einen Textausschnitt (ein so genanntes Snippet) zu erhalten, in dem die Suchterme hervorgehoben sind. Um ein solches Suchinterface auch mit Solr implementieren zu können, ist es möglich, Suchresultate mit Snippets anzufordern, die ein Highlighting enthalten. Dazu müssen an den oben angegebenen Query Request lediglich Highlighting-Informationen angehängt werden: &hl=true&hl.fl=beschreibung&hl.fragsize=30 würde aus der Beschreibung einen maximal 30 Tokens großen Snippet generieren, der Highlighting-Informationen enthält. Auch diese Snippets werden über das Solr-Antwort-XML ausgeliefert.

[ header = Seite 3: Solr Facetting ]

Solr Facetting

Wird eine Produktsuche implementiert, ist eine flache Liste von Suchergebnissen oft nicht wünschenswert. Vielmehr soll Nutzern die Möglichkeit gegeben werden, in die Suchergebnisse leicht hineinzunavigieren. Dazu werden üblicherweise Facetten genutzt: Im Beispiel-Screenshot von Sourceforge wurde nach dem Wort „solr“ gesucht. Mittig finden sich die Suchergebnisse aus dem Index. Links davon befinden sich Vorschläge für weitere Query-Einschränkung jeweils mit der zu erwartenden Trefferanzahl für diese Einschränkung. Diese Vorschläge werden oft als Facettenbezeichnet. Solr unterstützt aktuell drei Arten, um Facetten zu berechnen. Abhängig von der Struktur der indexierten Dokumente sollte die passende Variante ausgewählt werden:

  • facet.query-Parameter erstellen die Facetten basierend auf einer beliebigen Query, die an den Index mitgeschickt wird.
  • Für auf Enums basierende Facetten iteriert Solr über alle indexierten Terme eines Felds und erstellt für jeden Term einen entsprechenden Filter. Diese Art der Facettierung funktioniert vor allem für jene Felder sehr gut, die vergleichsweise wenige Einträge haben. In unserem Beispiel ist der Typ eines Getränks dafür gut geeignet.
  • Wurden hingegen im zu facettierenden Feld viele Terme indexiert, sollte die auf dem Field Cache basierende Facettierung benutzt werden: Dabei werden nacheinander alle Dokumente abgearbeitet. Für alle Terme, die dieses Dokument im zu facettierenden Feld enthält, wird der Wert entsprechend inkrementiert.

Um mit Solr facetierte Suchergebnisse anzufragen, ist wiederum die Suchanfrage um entsprechende Parameter zu erweitern: &facet=true&facet.field=typ&facet.query=preis:[0 TO 10]&facet.query=preis:[10 TO *]. Im angegebenen Beispiel werden die verschiedenen Kaffees nach Typ aufgesplittet. Außerdem wird dem Nutzer die Möglichkeit gegeben, die Resultatliste nach Preisintervallen einzuschränken.

Das Solr-Schema

Solr kommt mit für den Nutzer zwei wichtigen Konfigurationsdateien: Im Schema wird das Format der zu erwartenden Dokumente beschrieben. Außerdem enthält diese Konfiguration Informationen darüber wie Dokumente vorverarbeitet werden sollen: Mit welchem Tokenizer sollen Sätze in Worte aufgespalten werden? Sollen Worte auf ihren Wortstamm zurückgeführt werden?

Wie im Beispiel oben bereits angedeutet, bietet Solr mehr als eine reine Volltextsuche. Für Dokumente können eine Reihe von Feldern definiert werden, sie entsprechen quasi unterschiedlichen Dokumenteigenschaften. Als Beispiel soll eine Suchapplikation für einen Onlinekaffeeversand dienen. Ein Dokument entspricht in diesem Beispiel genau einem Produkt, das für den Versand zur Verfügung steht. Mögliche Felder sind der Preis des Produkts, die Beschreibung, die Kaffeesorte, der Name, eine Liste fester Geschmackseigenschaften. Der Preis wird im Index als Zahl abgelegt. Es soll möglich sein, die Resultate nach Preis zu sortieren. Falls im indexierten Dokument kein Preis angegeben wurde, soll der entsprechende Treffer immer an letzter Stelle in der Liste erscheinen. Die entsprechende Definition sieht dann folgendermaßen aus: <fieldType name=“preis“ class=“solr.TrieFloatField“ sortMissingLast=“true“ />

Der Name wird als String abgelegt, in der Verarbeitungskette soll er nicht verändert werden. Auch in der Liste von Geschmackseigenschaften soll an den Einträgen selbst nichts geändert werden, per Default soll jeder Kaffee aber „lecker“ sein, wenn nichts anderes angegeben ist. Auch hier soll eine Sortierung nach Eigenschaften möglich sein. <fieldtype name=“string“ class=“solr.StrField“ stored=“true“ default=“lecker“ />

Bei der Beschreibung sind einige Schritte mehr notwendig: Sie soll als String abgelegt werden. Damit sie aber durchsuchbar ist, soll der ankommende Text in einzelne Worte (Tokens) aufgespalten werden. Weiterhin sollen typische Stoppworte wie „der“, „die“, „das“, „ist“, die in allen Texten sehr häufig vorkommen und keine eigentliche Bedeutung tragen, gefiltert werden. Treffer sollen case-insensitiv gesucht werden. Die resultierende Konfiguration sieht dann aus wie in Listing 2.

<fieldType name="beschreibung" class="solr.TextField">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.StopFilterFactory words="stopwords.txt"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>

Solr bringt sehr viele eigene Analyzer und Filter mit. Darunter am häufigsten verwendet ist der WhiteSpaceTokenizer, der Texte anhand von Whitespaces auftrennt. Für englische Texte, deren Worte auf den jeweiligen Wortstamm zurück geführt werden sollen, ist besonders die EnglishPorterFilterFactory spannend. In vielen Fällen sinnvoll ist die Filterung von Stoppworten. Dazu existieren eigene Stoppwortfilter mit konfigurierbaren Stoppwortlisten.

Die Solr-Konfiguration

Zusätzlich zum Datenformat ist es möglich. in der solr.config allgemeinere Eigenschaften des Index zu bestimmen. Hier können Performance-Settings wie die Größe und Lebensdauer der Solr Caches eingestellt werden. Aber auch die Einschränkung der erlaubten Query-Typen und Indexoperationen (Update, Query, Delete) ist hier möglich. Abhängig von den zu erwartenden Nutzern ist es möglich, verschiedene Query Parser einzustellen. Beim LuceneQueryParserPlugin wird direkt die Queryparsing-Syntax von Lucene verwendet. Diese Option ist vor allem für Poweruser, die mit Lucene sehr vertraut sind, interessant. Für eine weniger technische Gruppe von Nutzern, die wenig komplexe Anfragen stellen, bietet sich das DisMaxQueryParserPlugin an.

Solr oder Lucene?

Auf der Suche nach einer freien Suchmaschine fällt den meisten Entwicklern auf den ersten Blick Lucene ein: Das Projekt existiert seit über zehn Jahren, hat eine lebendige Entwicklergemeinde, ist in vielen Applikationen erprobt und hat sich bewährt. Allerdings handelt es sich bei Lucene lediglich um eine Java-Bibliothek, die einen Suchindex implementiert. Integration, Konfiguration und Deployment sind Themen, die bei Lucene Java selbst außen vor gelassen wurden. Mit Apache Solr steht ein Projekt zur Verfügung, das Lucene neben typischen Integrationsschritten auch um viele weitere nützliche Features erweitert und so den Einsatz der freien Suchmaschine deutlich erleichtert und beschleunigt. Auf diese Weise nimmt Solr dem Entwickler einer Suchapplikation die schwierigsten Schritte ab. Solange es sich bei der anvisierten Suchmaschine nicht um eine Suche auf einem Mobilgerät handelt, oder low-level Such-, Filter- und Rankingalgorithmen ausgetauscht werden sollen, bietet sich Solr als Grundlage an. Insbesondere bei der Überlegung, von einem kommerziellen Enterprise Search Server hin zu Lucene zu migrieren, konnten gute Erfahrungen mit der Verwendung von Solr gesammelt werden. Weiterführende Informationen, die über einen „Erste-Schritte“-Artikel hinausgehen, sind bei IBM developer networks ( hier und hier) verfügbar. Informationen speziell zu den mit Solr möglichen Wildcard Queries sind ebenfalls online verfügbar.

Isabel Drost ist ASF member. Sie organisiert seit zwei Jahren das Apache Hadoop Get Together in Berlin und war Koorganisator der Berlin Buzzwords. Sie hat das Apache-Lucene-Unterprojekt Mahout mit gegründet und ist dort aktiver Committer. Isabel engagiert sich aktiv in den Communities der Apache-Projekte Lucene und Hadoop und ist regelmäßiger Referent auf namhaften Konferenzen rund um das Thema freie Software, Scalability, Lucene, Hadoop und Mahout. Sie möchte sich an dieser Stelle bei Simon Willnauer und Uwe Schindler für die Unterstützung bei diesem Artikel bedanken.
Geschrieben von
Isabel Drost
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.