Grails, FacetView und ElasticSearch, als Alternative zu Solr

von Christian Thoma

Einleitung

Von einer Suchlösung erwartet man, dass sie unkompliziert einzusetzen ist, dass die Ergebnisse schnell berechnet und zurückgeliefert werden. Weiterhin muss die Suchlösung sich an die Anwendungen anpassen und nicht umgekehrt. Eine hohe Verfügbarkeit der Suche und die Skalierung für große Datenmengen müssen gewährleistet sein.


Von ElasticSearch werden diese Erwartungen zu einem hohen Maße erfüllt. ElasticSearch ist ein auf Apache Lucene basierender Suchserver. Er wurde zu Anfang ausschließlich von Shay Banon entwickelt und unter der Apache Lizenz veröffentlicht.  Mit ElasticSearch kann leicht ein Cluster aufgebaut werden und der Index auf verschiedene Server verteilt werden. Hierfür wird ein Index in so genannte Shards aufgeteilt.  Diese Shards können auf mehrere Server verteilt werden. Somit kann die Last, für eine Suche in einem Index, auf mehrere Knoten verteilt werden. Jeder Knoten weiß, welche anderen Knoten für die jeweiligen Shards verantwortlich sind. Um eine Ausfallsicherheit gewährleisten zu können, werden Replicas verwendet. Ein Replica ist eine Dublette eines Shards. Das Routing und die Lastverteilung zwischen den Servern/Shards und Replicas bewerkstelligt ElasticSearch automatisch. 


Solr ist ebenfalls ein unter der Apache Lizenz veröffentlichter Suchserver. Vergleichen wir kurz beide Suchlösungen. Solr und ElasticSearch sind beides zwei schnelle, auf Apache Lucene basierende Suchlösungen. Bei einer einfachen „Ein Server“- Installation sind beide Lösungen nahezu gleichwertig. Bei manchen Anwendungsfällen, wie z. B. nur Indizierung, ist Solr schneller.


Sobald sowohl indiziert als auch gesucht und/ oder optimiert wird, ist die Performance von ElasticSearch wesentlich schneller. Das Setup für ein Cluster ist mit Solr schwieriger zu bewerkstelligen. Eine ElasticSearch-Lösung kann innerhalb von wenigen Minuten aufgesetzt werden. Von Anfang an zielte die Entwicklung von ElasticSearch darauf ab, verteilbar zu sein.


Indizes und das Schema des Indexes können bei ElasticSearch „on the fly“ erstellt werden. Es ist kein Neustart und keine neue Konfiguration notwendig. Solr unterscheidet zwischen Servern, die die Verwaltung des Clusters bewerkstelligen. Bei  ElasticSearch kann jeder Server die Aufgaben eines anderen übernehmen.  Zusätzliche Solr-Server im Cluster müssen konfiguriert werden. Einen ElasticSearch-Server fügt man dem Cluster durch das Starten hinzu.
ElasticSearch-Plugins gibt es mittlerweile für viele Frameworks. Für Grails, ein Web-Applikations-Framework, gibt es ein ElasticSearch-Plugin das die Version 0.18.7 unterstützt. Grails, in der Version 2.1.1, und das ElasticSearch-Plugin wurden für das folgende Setup verwendet. 


FacetView ist ein mit HTML/CSS/Javascript realisiertes Frontend für ElasticSearch. Es lässt sich sehr einfach installieren, konfigurieren und unterstützt die Suche mit Facetten.
ElasticSearch-head ist ein Plugin für ElasticSearch, das die Administration von ElasticSearch-Servern erleichtert.

Anwendungsfall

Adressdaten sollen innerhalb einer Grailsanwendung erstellt werden. Anderen Anwendungen soll es möglich sein die Adressdaten zu durchsuchen, ohne auf die Adressdatenbank zuzugreifen. 
Das Domänenmodell wird mit der Grailsanwendung abgebildet. Das Speichern und Indizieren der Daten erfolgt mit der Grailsanwendung und dem ElasticSearch-Plugin. FacetView wird als Suchoberfläche verwendet.

 

Vorgehensweise

1. Neues Grails Projekt erstellen. 
2. Erstellen der Domänenklasse (Adresse).

Die einfachste Möglichkeit die Instanzen einer Domänenklasse zu indizieren und suchen zu können, ist die Domänenklasse als “searchable = true” zu definieren. Standardmäßig werden alle Attribute der Klasse in den Index aufgenommen. Die Klasse besteht lediglich aus Attributen des Typs String.  Eine Adresse hat einen Namen, Straße, Hausnummer, Stadt, Adresstyp und Adressqualität.

Address.groovy 

package addresses

class Address {

      static searchable = true

    String name
    String street
    String houseNumber
    String city
    String addressType
    String addressQuality
    static constraints = {
    }
}

3. Controller und Views für die Domänenklasse erstellen. Mit dem folgenden Befehl werden diese in einer Grails Anwendung erstellt. generate-all addressdatabase..Address 
4. ElasticSearch-Plugin für Grails installieren. 
5. Konfiguration des elasticsearch-Plugins: 


DefaultElasticSearch.groovy 
client.hosts = [
          [host:'localhost', port:9300]
  ]
    client.transport.sniff = true
elasticSearch.client.mode = 'transport'

6. Installation des elasticsearch-head-Plugin, Installationsanleitung siehe: http://mobz.github.com/elasticsearch-head/ 
7. Starten von vier ElasticSearch-Knoten. Startdateien sind für Windows und Linux im /bin-Verzeichnis zu finden. 
8. Aufruf des ElasticSearch-head-Plugin, siehe URL unter Punkt 5. Es wurden 5 Shards erzeugt, jedoch keine Replicas (Replikationen eines Shards) erstellt. Es sollen jedoch zwei Replicas jedes Shards im Cluster verfügbar sein. Sollte ein Shard ausfallen, existieren Replicas des Shards, die anstatt dessen einspringen können. Es folgt ein Aufruf des Menüpunkts „Any Requests“ in der Cluster Administrations-Oberfläche, um die entsprechende Anweisung zu formulieren und abzuschicken.  

 9. Adressdatensätze in der Grails-Anwendung erstellen: Für unser Setup wurden 4.999.999 Adress-Datensätze und 50443 Zeitmess-Datensätze automatisiert erstellt. Wenn keine Exception in der Konsole der Grails-Anwendung erscheint und das Elasticsearch-Plugin wie beschrieben konfiguriert wurde, sollten die Daten nun im Cluster verfügbar sein. Dies kann in der Elasticsearch-head- Oberfläche kontrolliert werden.  
 
10. Installation von FacetView. Der Download erfolgt als zip-Datei und wird in ein beliebiges Verzeichnis extrahiert. Mit dem Attribut search_url  wird die URL zu einem ElasticSearch-Server konfiguriert. Den zu durchsuchenden Index und den gewünschten Typ kann man durch die URL definieren. In diesem Beispiel wird der Index „addresses“ und  der Typ „address“ durchsucht.  Als Facetten definieren wir die Stadt, die Adressqualität und den Adresstypen. Die Anzahl der Adressen, pro Seite, wird mit dem Attribut „paging“ auf 10 beschränkt.

Der erste Aufruf der Seite dauerte  1,09s. Darauf folgende Aufrufe bauten die komplette Webseite in ca. 700ms auf. Das Anzeigen der Ergebnisse, nach einer Suche über die Facetten oder das Input-Feld, benötigte zwischen 50 und 500 ms. Das Setup wurde lediglich auf einem Laptop installiert. Durch die Verteilung der Software auf zwei leistungsfähige Server könnte die Performance sicherlich positiv beeinflusst werden.
Ein kleiner Vergleich zum Schluss. Grails mit dem ElasticSearch-Plugin benötigte unter 1 ms, um eine Adresse zu indizieren. In der Standardkonfiguration benötigte das Solr-Plugin ca. 150 ms für eine Adresse.  Der Grund hierfür wurde nicht untersucht. Da das Solr-Plugin mehr als eine Woche benötigt hätte um ca. fünf Millionen Adressen zu erstellen wurde darauf verzichtet, die Performance bei der Suche  zu vergleichen. 

Fazit

Eine einfache prototypische Suche, die sich später gut skalieren lässt, ist mit frei verfügbarer Software innerhalb einer bis zwei Stunden realisierbar. Bei FacetView muss man kleine Fehler in Kauf nehmen. Diese sind in der Regel jedoch einfach zu beheben.
In diesem Beispiel wurden keine Optimierungsmöglichkeiten berücksichtigt. Mit dem Ergebnis bei ElasticSearch kann man jedoch sehr zufrieden sein. Die Antwortzeiten des ElasticSearch-Clusters waren gut. Bei größeren Datenmengen kann die Suche einfach skaliert werden. Das Indizieren benötigte sehr wenig Zeit. ElasticSearch- Cluster sind, zumindest bei moderater Datenmenge, einfach in der Handhabung. Durch die Replicas und die Verteilung der Shards kann eine hohe Ausfallsicherheit gewährleistet werden. 

Kategorien: Apache LuceneApache SolrElasticsearchGrails

Zurück