Über unsMediaKontaktImpressum
Tobias Kraft 06. Oktober 2015

Search Driven Applications mit Elasticsearch

Wird von Suche gesprochen, denken vermutlich die meisten Menschen an Google und sein schlichtes Sucheingabefeld und seine Volltextsuche. In Unternehmensapplikationen wurde in der Vergangenheit die Suchmaschine oftmals nur als Beiwerk integriert. In diesem Artikel wird gezeigt, dass Suche mehr als Volltextsuche ist und es klassische Anwendungsfälle gibt, bei denen es Sinn macht, eine Suchmaschine tiefer mit der Applikation zu integrieren. Außerdem zeigen die Anwendungsfälle, dass Suche nicht nur für große Datenmengen seine Daseinsberechtigung hat, sondern auch im "Kleinen" Mehrwert bietet.

So genannte Search Driven Applications sind durch zwei wesentliche Merkmale gekennzeichnet. Zum einen wird die Suche als Kernbestandteil der Applikation gesehen und stellt Daten für die Geschäftslogik bereit. Zum anderen dient der Suchserver als zentraler Lesespeicher, der die aktuellen Daten enthält.

Bei manchen Kunden hörte man in der Vergangenheit des Öfteren, dass die Suche momentan nicht aktuell ist oder zeitweise überhaupt nicht funktioniert. Bei Search Driven Applications steigt der Stellenwert des Suchservers, denn eine nicht funktionierende Suche bedeutet auch die Funktionsunfähigkeit der eigentlichen Anwendung. Abb.1 verdeutlicht das Szenario. Die schreibenden Zugriffe erfolgen weiterhin auf ein bzw. mehrere Quellsysteme. Die Daten der Quellsysteme werden regelmäßig zum Suchserver synchronisiert und stehen damit der Anwendung für die Nutzung zur Verfügung.

Zwangsläufig kommt die Frage nach dem Mehrwert dieser Art von Applikations-Architekturen auf. Hierzu werfen wir zunächst einen Blick auf potentielle Probleme von klassischen Applikationen. Die Ablage von Daten erfolgt in klassischen Anwendungen bei mehreren Datenquellen in unabhängigen Daten-Silos, so dass es aufwändig ist, Informationen und gemeinsame Sichten aus den Strukturen zu bekommen. Steigt die Datenmenge im Laufe der Zeit stetig, gestaltet sich die Skalierung in Bezug auf Performance und steigende Mengen auf Datenbankebene nicht immer einfach und ist gegebenenfalls ein kostspieliges Unterfangen. Häufige Änderungen des Datenbankschemas gestalten sich in mancher Hinsicht aufwändig, da beispielsweise Indexe überprüft, angepasst, sowie Neuanlagen erfolgen müssen.

Suchmaschinen können für die angesprochenen Bereiche hilfreiche Unterstützung liefern durch:

  • Konsolidierung von Daten
  • Einfache Skalierbarkeit
  • Flexible Abfragen und flexibles Schema

Neben Suchmaschinen gibt es natürlich weitere Prinzipien und Technologien, die auf die angesprochenen Probleme von klassischen Applikationen eingehen, wie bspw. die NoSQL-Datenbanken. Für die Veranschaulichung nutzen wir in diesem Artikel die Suchmaschine Elasticsearch [1].

Elasticsearch

Elasticsearch steht unter der Apache Lizenz 2.0 frei als Open Source-Produkt zur Verfügung. Technologisch basiert Elasticsearch auf Java und nutzt die ebenfalls freie verfügbare Such-Bibliothek Lucene [2]. Neben der klassischen Volltextsuche gibt es für Elasticsearch sowie für die meisten anderen Suchmaschinen heutzutage vielfältige weitere Anwendungsszenarien. Hierzu gehören neben den auch bei Search Driven Applications genutzten Möglichkeiten des Cachings und Speicherns auch die Geo-Suche, Analytics oder Log-File-Analysen. Gerade durch Log-File-Analysen konnte Elasticsearch in der Vergangenheit einen großen Bekanntheitsgrad in Zusammenhang mit dem ELK-Stack [3] erlangen.

Die Nutzung von Elasticsearch gestaltet sich recht einfach. Ein Grund hierfür ist, dass für sämtliche Kommunikation mit dem Suchserver JSON genutzt werden kann. Listing 1 zeigt eine triviale Suchabfrage und einen Ergebnis-Ausschnitt.

Listing 1:

Abfrage: 
POST /_all/_search
{
  "query": {
    "match": {
         "title" : "Search Driven Applications"
    }
  }
}

Ergebnis:
{
    "took": 15,
    "timed_out": false,
        "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.076713204,
        "hits": [
            {
                "_index": "talks",
                "_type": "talk",
                "_id": "34iBlv3v7Spy0pPwwEFyBrw",
                "_score": 0.076713204,
                "_source": {
                    "title": "Search Driven Applications",
                    "speaker": "Tobias Kraft",
                    "date": "2015-07-17T15:35:00.000Z",
                    "tags": [
                        "Java",
                        "Search"
                    ],
    ....           

Ein weiteres wesentliches Merkmal ist die Schemalosigkeit von Elasticsearch. Dies bedeutet, dass ein Index, der zur Daten-Ablage genutzt wird, dynamisch angelegt werden kann, ohne dass zuvor der Aufbau definiert wurde. Vor allen Dingen zu Beginn eines Projektes ist dies hilfreich, um schnelle Fortschritte zu erzielen. Man sollte natürlich trotz der Schemalosigkeit genau definieren, welche Daten wie abgelegt werden. Mit Plugins stellt Elasticsearch einen eleganten Mechanismus für Erweiterungen bereit. Dies können beispielsweise Plugins mit einer Oberfläche zur Administration des Servers sein, aber auch Erweiterungen hinsichtlich Themen wie Security oder Analyzing. Es stehen zahlreiche frei verfügbare Plugins zur Auswahl.

Aufbau der Datenstruktur

Damit Daten der Quellsysteme im Sucherserver zur Verfügung stehen, müssen sie über den Indexierungs-Prozess im Index aufgenommen werden. Dies ist ein mehrstufiger Prozess, der beispielhaft in Abb.2 skizziert ist. Es gibt die Möglichkeit, die Quellsysteme bei Änderungen immer komplett neu zu indexieren, was sehr lange dauert und deshalb ungeeignet für Search Driven Applications ist. Aus diesem Grund wird inkrementell indexiert. Wichtig ist hierbei, dass Änderungen auch dort Near Realtime im Index zur Verfügung stehen, was Elasticsearch gewährleistet. Unter Near Realtime versteht man im Bereich Suchmaschinen in der Regel, dass die Daten innerhalb einer Sekunde zur Verfügung stehen.

Beim Indexierungs-Prozess werden Daten der Quellsysteme zunächst als ein sogenanntes Document im JSON-Format bereitgestellt, was dem ersten Schritt in Abb.2 entspricht. Vor der Ablage im Index erfolgt das Analyzing des Inputs. Der Analyzing-Schritt kann in Elasticsearch konfiguriert werden. Im gezeigten Beispiel erfolgt ein Aufteilen in einzelne Wörter, Überführen in Kleinschreibung und schließlich das Zurückführen auf den Wortstamm. Die Ablage erfolgt in einem invertierten Index [4] abhängig von dem definierten Schema-Aufbau (Mapping). Im Mapping werden Datentypen für den Input oder auch die mehrfache Ablage des Inputfeldes definiert, z. B. als Originaltext und als auf den Wortstamm zurückgeführtes Feld. Wird kein Mapping definiert (schemalos), so berechnet Elasticsearch das Mapping selbst, was nicht immer zu den gewünschten Ergebnissen führt. Generell ist die Ablage der Daten im Vergleich zur relationalen Datenbank denormalisiert und kann damit zu performanteren Abfragen führen.

Verteilung der Daten

Neben dem Aufbau der Datenstruktur ist die Verteilung der Daten zur Ablage bei Suchmaschinen ein unerlässlicher Aspekt. Dies hat wesentlichen Einfluß auf die Skalierbarkeit, die Ausfallsicherheit sowie den Umgang mit großen Mengengerüsten. Hier setzt Elasticsearch auf ein Cluster-Modell, das aus mehreren Knoten auf verschiedenen Rechnern bestehen kann. Auf einem Knoten werden jeweils die Indexe mit den Daten abgelegt, wobei sich ein Index auch über mehrere Knoten spannen kann. Für einen Index werden wiederum Shards definiert, die einem Knoten zugeordnet sind.

Wir veranschaulichen dies anhand des Beispiel-Clusters mit den beiden Indexen "otcdrug" und "document" in Abb.3. Alle Daten des Index "otcdrug" werden in einem Shard abgelegt, der repliziert wird auf Knoten 2. Mit Replicas wird die Ausfallsicherheit erhöht und die Skalierung bei Leseabfragen kann einfach erfolgen. Durch dynamisches Hinzufügen von weiteren Knoten und Replicas ist eine zügige Skalierung mit Elasticsearch durchführbar.
Für den Index "document" sind 4 Shards mit Replizierung definiert. Diese verteilen sich automatisch auf die vorhandenen Knoten-Cluster. Vorteil ist hier, dass damit der Index über mehrere Knoten verteilt ist. Durch das Sharding stellen die Plattenkapazitäten einzelner Rechner keinen Engpass mehr für die Indexgröße dar.

Einsatzszenarien für Search Driven Applications

Nachdem anhand von Elasticsearch einige für Search Driven Applications essentielle  Funktionalitäten vorgestellt wurden, gehen wir auf mehrere Szenarien zur Integration von Suchmaschinen als Kernstandteil einer Applikation ein.

Vereinheitlichung

Ein typisches Anwendungsszenario für die stärkere Integration einer Suchmaschine innerhalb einer Anwendung ist die Vereinheitlichung verschiedener Datenquellen. Abb.1 zeigt beispielhaft auf, wie neben einer Datenbank auch Content-Management-Systeme oder das Dateisystem über die Suche verfügbar gemacht werden. Die schreibenden Zugriffe gehen direkt auf das Quellsystem, die lesenden Zugriffe nutzen dagegen den Index. Durch Speicherung in einem Index können die Informationen verschiedener Quellsysteme einfach innerhalb einer Liste angezeigt werden. Da die lesende Zugriffsschicht für alle Backend-Systeme gleich ist, können in diesem Bereich auch Kosteneinsparungen durch einmalige Entwicklung erzielt werden.

Neben der Harmonisierung von verschiedenen Backend-Systemen ist mit Suchmaschinen die Vereinheitlichung innerhalb eines Systems umsetzbar. Sollen aus einer Datenbank beispielsweise in einer Listenansicht Mitteilungen und Dokumente angezeigt werden – mit Funktionalitäten zur Blätterung, Sortierung und Filterung –, kann dies ansatzweise über eine Datenbank-View gelöst werden. Falls die Filterung Dokumenteninhalte mit einbeziehen soll, gestaltet sich dies über eine Suchmaschine komfortabler.

Pflegedialoge

Viele Applikationen verfügen für die Datenbearbeitung über CRUD-Dialoge. Ausgangspunkt für die Pflegedialoge ist in der Regel eine Liste wie in Abb.4 dargestellt. In diesem Beispiel werden Mitteilungen gepflegt, die mit entsprechenden Tags zur Kategorisierung versehen werden können. Aus relationaler Datenbanksicht gibt es hierfür die Haupttabelle "Mitteilungen", die über eine n:m-Beziehung mit der Tag-Tabelle verbunden ist. Abhängig vom Anwendungsfall enthalten Listen-Dialoge viele Einträge, so dass eine Suchfunktionalität wünschenswert ist. Verfügt die Applikation nur über eine Datenbank, so erfolgt die Suche durch eine UND-Verknüpfung der eingegebenen Suchbegriffe. Da in diesem Fall zwei Tabellen verknüpft und durchsucht werden, ist die SQL-Abfrage, wie in Listing 2 zu sehen, etwas komplexer. Aufgrund der Notwendigkeit des Findens von Textausschnitten wird mit dem Like-Operator gearbeitet, was bei steigenden Datenvolumen und vielen Suchkriterien zu langsamen Abfragen führen kann. 

Listing 2:

select * from wdb_news n
inner join ex_taglink tl
  on n.id = tl.object_id
inner join ex_tag t
  on tl.tag_id  = t.id
where
(n.title like '%Geschäft%'
  or n.text like '%Geschäft%'
  or t.name like '%Geschäft%'

and
(n.title like '%Vertrieb%'
  or n.text like '%Vertrieb%'
  or t.name like '%Vertrieb%'

and
(n.title like '%Aussendienst%'
  or n.text like '%Aussendienst%'
  or t.name like '%Aussendienst%'
);

Steht jedoch ein Suchserver wie Elasticsearch zur Verfügung, gehen die schreibenden Operationen direkt auf die Datenbank und die Listenzugriffe erfolgen über die Suche. Listing 3 zeigt, wie übersichtlich sich die Suchabfrage für das Beispiel aus Abb.4 gestaltet. Durch Near Realtime stehen geänderte Einträge direkt nach den Schreiboperationen auf die Quellsysteme in der Liste bereit.

Listing 3:

POST /_all/_search
{
  "query": {
    "match": {
      "_all": {
        "query": "Vertrieb Geschäft Aussendienst",
        "operator": "and"
      }
    }
  }
}

Berechtigungen und Personalisierung

Die Implementierung von Berechtigungen auf Datensatzebene kann sich in einer relationalen Datenbank schnell zu einem Performance-Problem im Bereich von Listen aufschaukeln.
Verfolgen wir das Beispiel aus Abb.4 weiter, so kann man sich einfach vorstellen, dass innerhalb einer Firma Mitteilungen für Mitarbeiter abhängig von ihrer Position oder Abteilung angezeigt werden. Hierfür wird einer Mitteilung in der Datenbank die jeweilige Berechtigung zugewiesen. Im Index werden die Berechtigungen ebenfalls mit übernommen, so dass sie in den Suchanfragen mit einbezogen werden können. Listing 4 zeigt die Erweiterung der Abfrage, wobei die Berechtigungen des abfragenden Mitarbeiters als Filter-Bedingung aufgenommen werden.

Listing 4:

POST /_all/_search
{
"query": {
"filtered": {
"query": {
"match": {
"_all": {
"query": "Vertrieb Geschäft Aussendienst",
"operator": "and"
}
},
"filter": { "term": { "right": "ROLE_ADMIN" }}
}
}
}

Navigation über Facetten

Elasticsearch verfügt über die Funktionalität der Aggregations mit deren Hilfe Kategorisierungen erstellt werden können. Diese Funktionalität ist oftmals bekannt von Shop-Systemen im Bereich E-Commerce. In Systemen wie Amazon kann beispielsweise im Bereich der Bekleidungen nach Kategorien wie Hose oder Hemd selektiert werden. Aggregations berechnen ihre Ergebnisse in Realtime, abhängig von den Bedingungen der Abfrage und sie sind außerdem hierarchisch schachtelbar. In einem Online-Shop kann über die Hierarchie-Funktionalität beispielsweise zunächst eine Gliederung nach Schuh-Typ wie Stiefel oder Sandalette berechnet werden und darunter jeweils eine preisliche von/bis-Kategorisierung aufgeführt werden.

Nicht nur im Bereich E-Commerce sind Aggregations nützlich, sondern sie können auch als Navigatoren in einer Webanwendung genutzt werden. In Listing 5 wird eine Abfrage zum Auswählen von Veranstaltungen dargestellt, die einen Drilldown nach Kriterien wie Land oder Veranstaltungsdatum ermöglicht.

Listing 5:

POST /events/_search
{
"aggs": {
"locations": { "terms" : { "field" : "category" } },
"country": { "terms" : { "field" : "country" } },
"begindate" : {
"date_range" : {
"field" : "begin_date",
"format" : "yyyy-MM-dd",
"ranges" : [
{ "from": "now-1M/M"},
{ "from": "now-3M/M"},
{ "from": "now-6M/M"}
]
}
}
}
}

Fallstricke und Aufwände

Die Verwendung einer Suchmaschine als Kernbestandteil einer Applikation bringt nicht nur Vorteile, sondern hält auch einige Fallstricke bereit, die der Beachtung bedürfen. Als zusätzliches System erhöht ein Suchserver die Komplexität der Architektur. Es ist insbesondere darauf zu achten, dass die Suchmaschine mit den Datenquellen synchron gehalten wird.

Stellvertretend sollen hier Transaktionen erwähnt werden. Erfolgen in einer Transaktion mehrere Schreiboperationen auf die Datenbank und nach jeder Operation wird ein Aufruf des Such-Servers zur Aktualisierung des Indexes ausgeführt, ist die Gefahr des Auseinanderlaufens der Systeme gegeben. Ist beispielsweise die letzte Schreiboperation nicht erfolgreich, wird die Transaktion komplett zurückgerollt. Die bereits an den Suchserver geschickten Aufrufe aktualisieren allerdings bereits den Index. In diesen Fällen ist es sinnvoller, die Aktualisierung des Index erst anzustoßen, nach dem eine Transaktion erfolgreich durchgeführt wurde.

Die Fehlersuche und das Nachstellen von Produktionsproblemen ist durch die Mehrfachhaltung der Daten komplexer. Mit der Suche kommt ein weiteres System als potentielle Ursache für Fehler in den Fokus, das untersucht werden muss. Als eigenständige Installation in der Systemlandschaft bedarf ein Suchserver ebenfalls der Einbeziehung von Betriebsaspekten. Neben Aufwänden für die Installation werden im Idealfall separate Hardware-Ressourcen bereitgestellt, die ebenfalls Kosten verursachen.

Zu weiteren Betriebsaufgaben zählt das Monitoring des Suchservers oder die Analyse und Zusammenführung von entstehenden Log-Dateien auf den verschiedenen Systemen. Ein Suchserver bedarf der Absicherung, um Zugriffe für unberechtigte Benutzer zu verhindern. Werden keine Maßnahmen ergriffen, ist Elasticsearch standardmäßig ungeschützt und stellt deshalb ein entsprechendes Risiko dar. Eine einfache Möglichkeit des Schutzes ist die Nutzung einer Firewall (z. B. iptables unter Linux), um damit nur Zugang von Rechnern der Applikation zuzulassen. Mit dem kostenpflichtigen Plugin Shield [5] bietet die hinter Elasticsearch stehende Firma elastic Funktionalitäten zur Authentifizierung und Autorisierung innerhalb des Suchservers.

Erweiterte Nutzung von Suchmaschinen

Die engere Einbeziehung von Suchmaschinen in eine Applikation stellt auch Möglichkeiten für neue oder erweiterte Anwendungsszenarien wie die gezeigten Aggregations bereit. Hierzu gehören ebenfalls die Nutzung von Fuzzy Search oder von Synonymen. Ist beispielsweise ein Vergleichen von ähnlichen Produkten verschiedener Hersteller nicht direkt möglich, da kein eindeutiger Kenner existiert, ist ein automatisches Vergleichen anhand des Namens mit Hilfe von Fuzzy Search denkbar.

Autor

Tobias Kraft

Tobias Kraft beschäftigt sich bei der exensio GmbH mit der Architektur und Umsetzung von Enterprise-Portalen, Web-Applikationen und Such-Technologien basierend auf dem Java-Stack sowie dem Grails-Framework. Des Weiteren ist er...
>> Weiterlesen
Buch des Autors:

botMessage_toctoc_comments_9210