Immer flexibel

Mit ElasticSearch betritt ein auf Apache Lucene basierendes Open-Source-Paket die Bühne für Suchserver. Prädestiniert für den Cloud-Einsatz, muss es sich an Solr, dem ebenfalls auf Lucene setzenden Suchserver, messen lassen.

In Pocket speichern vorlesen Druckansicht 7 Kommentare lesen
Lesezeit: 9 Min.
Von
  • Peter Karich
Inhaltsverzeichnis

Shay Banon arbeitete an der dritten Version seiner auf Apache Lucene aufbauenden Java-Suchmaschine Compass (siehe „Onlinequellen“ [a]). Dabei realisierte er, dass große Teile neugeschrieben werden müssten, um seine Anforderungen an ein skalierbares Suchverfahren zu erfüllen. Er entschied sich für einen von Grund auf neu gestalteten Ansatz. Bei der Umsetzung lag ein Designschwerpunkt auf der Skalierbarkeit bei gleichzeitig einfacher Bedienung. Das Funktionsspektrum von Lucene, jedoch nicht dessen Komplexität, wollte Banon an Programmierer weiterreichen. Sie sollten sich nicht um das Caching oder gar um die Lucene-Interna wie Reader/Writer kümmern müssen. Weiterhin sollte die neue Version von Beginn an echtzeitfähig sein. Ein modulares System sollte das Hinzufügen neuer Features erleichtern und die Konfiguration per API erlauben.

All das hat Shay Banon mit ElasticSearch [b] realisieren können und damit eine der derzeit fortgeschrittensten dezentralisierten Suchlösungen auf Open-Source-Basis geschaffen. Informationen zur Entstehung liefert der Kasten „Lucenes Erben“, weitere Details finden sich in seinem Blog [c]. Zu den größeren Nutzern gehören Klout, Mozilla und StumbleUpon (siehe Alle Links).

Bis heute ist Apache Solr der gefühlte Liebling vieler Open-Source-affiner Unternehmen, die Suchtechniken einsetzen. Daher dient es im weiteren Artikel als Vergleichsmaßstab. Natürlich existieren viele freie Projekte, die ein ähnliches Ziel wie ElasticSearch verfolgen. Der Kasten „Potenzielle Alternativen“ stellt einige interessante Projekte vor.

Nicht zu unterschätzen sind auch die Such-Hosting-Dienste, wie das vor wenigen Monaten an LinkedIn verkaufte IndexTank. Die Suche dieser Dienste nutzt meist angepasste Open-Source-Pakete und bietet Enterprise-Suche ohne großen Installations- oder Administrationsaufwand.

Dieser Artikel zeigt anhand von Beispielen die Vor- und auch Nachteile von ElasticSearch auf. Dabei sollte man immer die gerade aktuellen Versionsnummern im Hinterkopf behalten – Version 0.18.7 für ElasticSearch und 3.5 für Apache Solr. Denn beide Projekte entwickeln sich rasant weiter.

Für das Installieren lädt man die aktuelle Version von der Projektseite herunter. Wer gleich auf der Amazon Cloud starten möchte, findet auf der Homepage von ElasticSearch geeignete Tutorials, die die notwendigen Konfigurationsänderungen und Plug-ins beschreiben [d]. Anschließend kann man über das Kommandozeilen-Tool curl Suchanfragen via ElasticSearch starten:

curl -XGET
'http://localhost:9200/_cluster/state?pretty=true'

Alternativ kann die Anfrage mit dem Java-Client erfolgen:

TransportClient client = new TransportClient();
client.addTransportAddress(new InetSocket TransportAddress(url, port));
client.admin().cluster().prepareState().execute(). actionGet().getState();

Anwender können die JSON-Abfrage (JavaScript Object Notation) bei Bedarf über das Frontend elasticsearch-head (siehe Screenshot, [e]) per Browser absetzen. Ein weiteres nützliches Tool ist BigDesk [f], das sich gut für ein Kurzzeit-Monitoring von Speicher und CPU eignet.

Tauchen beim Installieren oder später Schwierigkeiten oder Fragen auf, lassen sich diese meist in der Mailingliste oder per IRC klären [g, h].

Hauptsächlich für Anfragen steht ein grafisches Browser-Frontend bereit.

Vor der Suche steht zunächst der Prozess, der die Dokumente an die Suchmaschine übergibt – im Englischen Feeding oder Indexing benannt. Dabei erstellt Lucene einen invertierten Index, was man sich wie ein Wortverzeichnis eines Buches vorstellen kann: Die Wörter (korrekter: die Token) verweisen auf die Dokumente, in denen die Token vorkommen, und speichern unter Umständen noch zusätzliche Informationen wie die Positionen ab. Durch Bit-Operationen lässt sich dann leicht und vor allem schnell herausfinden, welche Dokumente zwei oder mehr Terme gleichzeitig beinhalten. Verweist beispielsweise das Token „michael“ auf die Dokumente 1, 2 und 7 und „jackson“ auf 2, 7, 9 und 14, dann führt eine Suche nach „michael jackson“ die AND-Operation dieser beiden Bitvektoren aus. Die Ergebnisdokumente, die beide Token enthalten, sind 2 und 7.

In ElasticSearch gibt man beim Indexieren eines Dokuments dessen ID (zum Beispiel „no-1“) sowie den Typ („shoe“) und den Index („shoes“) des Dokuments an:

curl -XPUT http://localhost:9200/shoes/shoe/no-1 -d '{
"name" : "left shoe",
"description" : "fits to the right one",
"category" : "sport"
}'

Existiert eine dieser Komponenten noch nicht, erzeugt ElasticSearch sie automatisch. Das Analogon per Java-API:

Map<String, Object> map = new HashMap <String, Object>();
map.put("name", "left shoe");
map.put("description", "fits to the right one");
map.put("category", "sport");
client.prepareIndex("shoes", "shoe", "no-1").setSource(map).execute().actionGet();

Felder vom Typ String indexiert der Server automatisch. Ist dies nicht gewünscht, muss man bei der Definition in einer Mapping-Konfigurationsdatei oder per API “index“:“no“ angeben.

Wie schon erwähnt, dauert es eine kurze Zeit (Echtzeitlatenz), bis das Dokument nach dem Indexieren auffindbar ist. Diese Zeit ist konfigurierbar und auf eine Sekunde voreingestellt. Den Wert kann man vergrößern, um das Indexieren zu beschleunigen. Unter Umständen (beispielsweise bei automatischen Tests) sollte man das sofortige Auffinden über die Operation refresh erzwingen.

Zusätzlich speichert ElasticSearch alle Felder unabhängig vom Typ in einem Feld _source und alle String-Felder in einem indexierten Sammelfeld _all. Letzteres dient dazu, Anfragen an alle Felder gleichzeitig zu richten. Das _source-Feld ist nicht indexiert, man kann es bei Bedarf auch komprimieren oder ganz weglassen. Seine interessanteste Eigenschaft ist jedoch, dass es bei GET-Anfragen via ID in Echtzeit, also ohne Latenz, zur Verfügung steht. Darüber lässt sich ElasticSearch ohne Weiteres als NoSQL-Speicher verwenden [i].

Mehr Infos

Potenzielle Alternativen

OpenSearchServer: Softwarepaket für Suchlösung: inklusive Web-Crawler und Suchserver, der auch auf Lucene basiert. GPL (v3) lizenziert.

Riak Search: Verteilter, echtzeitfähiger Volltext-Suchserver der auf Riak, dem Key-Value-Speicher, basiert. Apache (v2) lizenziert.

SenseiDB: Verteilter, echtzeitfähiger Volltext-Suchserver, der bei LinkedIn im Einsatz ist. Apache (v2) lizenziert. Das Projekt ist erst seit einigen Wochen auf dem Markt.

Sphinx: Eine Bibliothek zur Volltextsuche, meist in Verbindung mit MySQL genutzt. GPL (v2) lizenziert.

Solandra: Verteilter, echtzeitfähiger Volltext-Suchserver, der Solr und Cassandra kombiniert. Apache (v2) lizenziert. Der Entwickler Jake Luciani war auch Autor des jetzt verworfenen Lucandra.

Auch hier sind die Unterschiede zu Apache Solr offensichtlich: Zum einen muss man mit Solr explizit die Dokumente mit einem commit-Aufruf durchsuchbar machen, was viele Ressourcen (CPU, Festplatte) bindet und gerade bei vielen Dokumenten mehrere Sekunden dauern kann. Zum anderen gestaltet sich die Handhabung mehrerer Indizes mit Solr schwierig: Man muss genau wissen, wo Solr die Indizes erstellen und welche Konfigurationsdatei dabei jeweils zum Einsatz kommen soll et cetera. Weiter legt Solr für jeden Index eine Konfigurationsdatei an und nicht pro Typ. Dies ist besonders hinderlich beim Erstellen vieler Indizes eines Typs. Dafür benötigt jeder einzelne die gleiche Konfiguration.

Sieht man sich die Java-API etwas genauer an, zeigt sich ein weiterer Unterschied zu Solr: Die komplette API von ElasticSearch ist nicht blockierend ausgelegt. Das heißt, anstelle der Funktion actionGet() könnte man auch einen Listener hinzufügen, der erst zu einem späteren Zeitpunkt nachfolgenden Code aufruft und den aktuellen Thread nicht blockiert.

Wer sich mit verteilten Systemen beschäftigt, stößt immer wieder auf Begriffe wie Shards, Replika, Nodes und Cluster. Das Glossar auf Seite 70 liefert für diesen Artikel relevante, kurze Erläuterungen dazu.

Das Erstellen neuer Indizes ist sehr einfach – es erfolgt automatisch beim Indexieren des ersten Dokuments. Auf Wunsch lässt sich dieser Vorgang kontrollieren. Wer etwa nur drei Shards und ein Index-Replika möchte, kann dies über den folgenden Befehl steuern:

curl -XPUT 'http://localhost:9200/shoes/' -d '{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}}'

oder via Java:

Settings s = ImmutableSettings.settingsBuilder()
.put("index.number_of_shards", 3)
.put("index.number_of_replicas", 1).build();
client.admin().indices().create(new CreateIndexRequest(indexName)
.settings(s)).actionGet();

Bei Solr muss ein Programmierer einen zu großen Index selbst aufteilen. Er muss angeben, welches Dokument wohin kommt. ElasticSearch gibt dem Programmierer die Möglichkeit, dies mit den Shards gleich beim Erzeugen eines Index festzulegen. Auch die Anfrage bleibt unabhängig von den Shards oder Replika: Der Benutzer muss nicht wissen, welche Server zu befragen sind – ElasticSearch leitet das Anliegen immer an die richtigen Nodes weiter. Darüber hinaus muss man für das Sharding nicht mehrere Instanzen aufsetzen, es genügt, so viele ElasticSearch-Instanzen wie nötig zu starten – die Instanzen sind unabhängig von Shard- oder Replika-Konfiguration. Im Beispiel existieren die drei Shards innerhalb einer Instanz. Kommt eine neue Instanz hinzu, verschiebt ElasticSearch sie automatisch. Dabei verteilt es die Shards gleichmäßig auf die im Cluster befindlichen Instanzen.

Ein weiterer großer Unterschied ist, dass ElasticSearch auf allen Instanzen durch „Push-Replikation“ auf dem aktuellen Stand ist. Der Master indexiert eintreffende Dokumente auf den notwendigen Slaves noch einmal. Bei Solr dagegen holen sich die Slaves neue (Lucene-)Segmente vom Master. Letzterer fügt regelmäßig kleinere Segmente zu größeren zusammen. Diese wiederum müssen die Slaves erneut holen, da sie neue Dokumente enthalten könnten. Solr holt sich diese Pakete, obwohl ein Großteil der Daten unter Umständen auf dem Slave schon vorhanden ist. ElasticSearch vermeidet durch die „Push-Replikation“ nicht nur jede Menge Netz-IO-Operationen – was vor allem für die Amazon-Cloud aus Kostengründen interessant ist –, sondern bleibt auch mit mehreren Instanzen echtzeitfähig und erhöht so die Ausfallsicherheit. Dank der gleichberechtigten Instanzen kann der Master leicht die Rolle mit einem beliebigen Slave tauschen. Dieser Rollenwechsel ist bei Solr um einiges schwieriger und fehleranfälliger – nicht zuletzt, weil die Änderungen des Masters meist nicht in Echtzeit vorliegen. So müssten die letzten Dokumente ermittelt und neu indexiert werden, wenn der Master ausfällt.

Den vollständigen Artikel finden Sie in iX 3/2012.

Alle Links: www.ix.de/ix1203067 (avr)