Elasticsearch – Ein praktischer Einstieg

Code

Beispielcode

Die im Buch verwendeten Beispiele können vom GitHub-Repository des Buchs heruntergeladen werden.

Zum Selbermachen

Im Buch finden sich einige Übungen, die jeweils mit Zum Selbermachen markiert sind. Im Folgenden finden sich einige Hinweise zu den ersten Aufgaben.

Seite 16, Indizierung von Dokumenten

Indizieren Sie weitere Dokumente für Vorträge. Was passiert, wenn einzelne Felder im Dokument nicht enthalten sind? Können die Werte aller Felder durch eine Suche gefunden werden?

Dokumente können entweder mit eigener oder generierter ID angelegt werden. Felder können auch weggelassen werden und die Kardinalität einzelner Felder kann unterschiedlich sein.

POST "http://localhost:9200/conference/talk/" -d'
{
    "title": "Clickstream-Analyse mit Apache Spark",
    "speaker": [ "Andreas Zitzelsberger", "Josef Adersberger" ],
    "date": "2015-09-30T11:35:00.000Z",
    "conference": {
        "name": "data2day",
        "city": "Karlsruhe"
    }
}'

curl -XPUT "http://localhost:9200/conference/talk/123" -d'
{
    "title": "Indexing Tweets with Logstash",
    "speaker": "Florian Hopf",
    "conference": [
        {
            "name": "Elasticsearch Usergroup FFM",
            "city": "Frankfurt"
        }, {
            "name": "Search Meetup Karlsruhe"
        }
    ]
}'

Im ersten Beispiel sind zwei Sprecher angegeben, im zweiten zwei Konferenzen, dafür allerdings kein Datum. Selbstverständlich muss der Code oder die Anwendung, die die Antwort auswertet, dann auch mit fehlenden Werten umgehen können.

Die Dokumente können durchsucht werden, auch Werte in Subdokumenten können gefunden werden, beispielsweise in den eingebetteten Konferenzdokumenten.

curl -XGET "http://localhost:9200/conference/talk/_search?q=Karlsruhe"

Seite 21, Suche auf Feldern

Verhält sich die Suche über match auf allen unseren Feldern gleich? Wie würde eine Abfrage nach dem Konferenznamen oder der Konferenzstadt aussehen? Können wir auch auf dem _all-Feld suchen?

Die Suche funktioniert auf den Textfeldern wie erwartet. So kann beispielsweise auch innerhalb der Konferenzstädte gesucht werden.

curl -XPOST "http://localhost:9200/conference/talk/_search" -d'
{
    "query": {
        "match": {
           "conference.city": "karlsruhe"
        }
    }
}'

Eine Suche auf dem Datum ist ebenfalls möglich.

curl -XPOST "http://localhost:9200/conference/talk/_search" -d'
{
    "query": {
        "match": {
           "date": "2015-09-30T11:35:00.000Z"
        }
    }
}'

Auch das _all-Feld verhält sich wie erwartet.

curl -XPOST "http://localhost:9200/conference/talk/_search" -d'
{
    "query": {
        "match": {
           "_all": "karlsruhe"
        }
    }
}'

Seite 26, Suche auf not_analyzed-Feld

Was passiert, wenn wir nun mittels einer match-Abfrage auf dem tags-Feld suchen? Ist die Suche noch unabhängig von Groß- und Kleinschreibung? Unterscheidet sich das Verhalten, wenn man ohne Angabe eines Felds über den q-Parameter sucht? Wie kann das Verhalten erklärt werden?

Die Suche auf dem als not_analyzed markierten Feld funktioniert nach wie vor für einen großgeschriebenen Begriff, allerdings nicht mehr für einen kleingeschriebenen.

curl -XPOST "http://localhost:9200/conference/talk/_search" -d'
{
    "query": {
        "match": {
           "tags": "lucene"
        }
    }
}'

Das liegt daran, dass der Term kleingeschrieben im Index hinterlegt ist.

Eine Suche über den Query-String ohne Angabe eines Feldes führt allerdings noch zum Ergebnis.

curl -XGET "http://localhost:9200/conference/talk/_search?q=lucene"

Auch hier ist wieder das _all-Feld die Ursache. Wir haben das Mapping lediglich für das tags-Feld angepasst, für das _all-Feld wird nach wie vor der Standard-Analyzer verwendet, der die Terme in Kleinbuchstaben umwandelt.

Seite 32, Terms-Aggregationen

Können wir auch mehrere Aggregationen auf einmal anfordern? Wie sieht das Ergebnis für eine Terms-Aggregation aus, wenn sie auf einem anderen Feld, z. B. speaker, angewandt wird? Wie sieht eine Abfrage kombiniert mit einem query-Element aus?

Aggregationen können auch mehrfach hinterlegt werden und mit einer query kombiniert werden.

curl -XPOST "http://localhost:9200/conference/talk/_search" -d'
{
   "query": {
      "match_all": {}
   },
   "aggs": {
      "tags_facet": {
         "terms": {
            "field": "tags"
         }
      },
      "city_facet": {
         "terms": {
            "field": "conference.city"
         }
      }
   }
}'

Wenn Daten mit der Terms-Aggregation ausgelesen werden sollen ist es wichtig diese Daten speziell zu verarbeiten, beispielsweise durch die Angabe von not_analyzed. Ansonsten werden unerwartete Ergebnisse zurückgeliefert, beispielsweise bei einer Terms-Aggregation für die Sprecher, bei der Vor- und Nachname getrennt zurückgeliefert werden.

 {
   "aggregations": {
      "speaker_facet": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            {
               "key": "adersberger",
               "doc_count": 1
            },
            {
               "key": "andreas",
               "doc_count": 1
            },
            {
               "key": "florian",
               "doc_count": 1
            },
            {
               "key": "hopf",
               "doc_count": 1
            },
            {
               "key": "josef",
               "doc_count": 1
            },
            {
               "key": "zitzelsberger",
               "doc_count": 1
            }
         ]
      }
   }
 }

Seite 35, Search-Template

Hinterlegen Sie eine Kombination aus Query und Aggregation als Search-Template.

curl -XPUT "http://localhost:9200/_search/template/by-title-with-aggregation" -d'
{
   "template": {
      "query": {
         "match": {
            "title": "{{title}}"
         }
      },
      "aggs": {
         "tags_facet": {
            "terms": {
               "field": "tags"
            }
         }
      }
   }
}'

Seite 41, German-Analyzer

Fallen Ihnen Namen ein, die mit dem German-Analyzer nicht mehr gut zu unterscheiden wären? Kontrollieren Sie die Vermutung anhand der _analyze-Funktionalität.

Bei Begriffen, die nicht unter die normalen Regeln der deutschen Sprache fallen kann dieses Verhalten leicht auftreten. Beispielsweise werden die Namen Meyer, Meyen und Mey alle auf den Term mey zurückgeführt.

curl -XGET "http://localhost:9200/conference/_analyze?analyzer=german&text=Meyer Meyen Mey"

Seite 48, Inhalte mehrfach indizieren

Konfigurieren Sie das Mapping so, dass die unter tags hinterlegten Schlagwörter sowohl über eine durch den Analyzer verarbeitete Abfrage gefunden werden können, aber auch durch die exakte Abfrage, wie wir sie in Kapitel 2 konfiguriert haben. Wie sieht eine Abfrage aus, die auf den Schlagwörtern und dem Titel sucht und nach einem Schlagwort filtert?

Oftmals wird als Name für ein Feld, das den Originalinhalt enthält das Suffix raw angehängt. Das Mapping für die Schlagwörter kann dann folgendermaßen aussehen.

curl -XPUT "http://localhost:9200/conference/talk/_mapping" -d'
{
   "talk": {
      "properties": {
         "tags": {
            "type": "string",
            "analyzer": "german",
            "fields": {
               "raw": {
                  "type": "string",
                  "index": "not_analyzed"
               }
            }
         }
      }
   }
}'

Um auf dem Titel und den Schlagwörtern zu suchen und nach einem Schlagwort zu filtern kann die folgende Abfrage verwendet werden.

curl -XPOST "http://localhost:9200/conference/talk/_search" -d'
{
    "query": {
        "filtered": {
           "query": {
                "multi_match": {
                   "query": "Elasticsearch",
                   "fields": ["title", "tags"]
                }
           },
           "filter": {
               "term": {
                  "tags.raw": "Lucene"
               }
           }
        }
    }
}'