Verschachtelte UND und ODER Queries mit Elasticsearch

Verschachtelte UND und ODER Queries mit Elasticsearch

Dies ist der dritte Teil meiner Serie zu elastic search. Im letzten, dem zweiten Teil ging es darum, wie du Dokumente in elastic search indexieren kannst und wie eine einfache abfrage aussehen kann. In diesem Teil soll es darum gehen, wie Anfragen gefiltert werden können und wie diese Filter mit UND / ODER verknüpft werden können.

Elastic Search Index mit Testdaten vorbereiten

Um eine Datenbasis für ein paar Test zu haben indexieren wir für als Beispiel Länder mit Einwohnerzahlen und der Währung die im jeweiligen Land als Zahlungsmittel gilt:

curl -PUT -d '{"name": "spain", "currency": "EUR", "residents": 47000000, "language": "spanish"}' http://localhost:9200/countries/europe
curl -PUT -d '{"name": "germany", "currency": "EUR", "residents": 81000000, "language": "german"}' http://localhost:9200/countries/europe
curl -PUT -d '{"name": "usa", "currency": "USD", "residents": 320000000, "language": "english"}' http://localhost:9200/countries/america
curl -PUT -d '{"name": "mexico", "currency": "MXN", "residents": 123000000, "language": "spanish"}' http://localhost:9200/countries/america
curl -PUT -d '{"name": "england", "currency": "GBP", "residents": 53000000, "language": "english"}' http://localhost:9200/countries/europe

Elastic search Query Filter und Filtered Queries

Im vorherigen Teil haben wir bereits eine einfache Query kennen gelernt, die mittel „match“ in einem Feld sucht.

Wenn wir die query aus dem vorherigen Workshopteil (Teil 2) auf unsere Beispieldaten anpassen, so sieht eine einfach match Query so aus:

 

POST http://localhost:9200/countries/_search
{
  "query": {
    "match": {
      "currency": "EUR"
    }
  }
}

Wenn man diese Query mit einer SQL Query vergleicht würde diese in etwa so aussehen:

 

SELECT * FROM countries where currency LIKE '%EUR%';

Im Suchkontext gibt es wichtige bereiche, zum einen das Filtern und zum anderen das Scoring, also in welcher Reihenfolge die Ergebnisse erscheinen.

Da die Reihenfolge in der Suche sehr sehr wichtig sind um optimale Ergebnisse zu erhalten gibt es hier entsprechend flexible Möglichkeiten.

Filter Query

In elastic search gibt es in einer Query zwei Kontexte.

Den Query Context - Das WO: In diesem Kontext sollte man Einschränkungen treffen, die das Scoring betreffen, also die Reihenfolge der Resultate. Es wird durch das „query“ Keyword im Querystring eingeleitet.


Den Filter Context - Das OB: Der Filterkontext trifft Einschränkungen auf die Ergebnismenge, also ob ein Dokument im Ergebnis ist oder nicht.

Elastic empfiehlt, wann immer es geht den Filter Context zu verwenden.

Neben der Query am Anfang, kann man also die selbe Ergebnismenge mit der folgenden Query bekommen:

{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ],
      "filter": [
        {
          "match": {
            "currency": "EUR"
          }
        }
      ]
    }
  }
}

In diesem Beispiel werden alle Dokumente abgefragt und die Ergebnisdokumente werden gefiltert auf den Term „currency: EUR“.

Das Filtered passiert hier nach der Anfrage. Bei Abfragen die häufig die gleichen Filter enthalten und eine große Ergebnismenge ausschliessen sind "Filtered Queries" zu bevorzugen, weil sie vor der Query ausgeführt werden.

 

Filtered Query

Eine weitere Variante ist die „Filteredquery“. Diese Query schränkt die Ergebnismenge von Begin ein.

 

Gerade bei großen Datenmengen ist diese Variante zu bevorzugen, da sie performater ist als eine "Filter" Anweisung innerhalb der Query.

 

{
  "query": {
    "filtered": {
      "filter": {
        "match": {
          "currency": "EUR"
        }
      }
    }
  }
}

Standardmässig, wenn keine Query angegeben wird, fragt elastic alle Dokumente ab und wendet den Filter an.

Filter mit UND / ODER kombinieren - Boolean Filter mit must und should

Oftmals möchte man mehrer Filter kombinieren mit und oder oder Kombination. In SQL wäre z.b. folgende Abfrage denkbar:

SELECT * FROM countries WHERE residents > 60000000 and language LIKE '%english%';

In diesem Fall würden wir erwarten alle Länder die mehr als 60000000 Einwohner haben und die Sprache englisch. Darauf passt in unserem Testdatensatz nur die USA

In Elastic kann man eine solche Query mit einer verschachtelten "boolean" Query erreichen mit "must" werden die beiden Filter kombiniert und mit einem logischen "UND / AND" ausgewertet:

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "match": {
                "language": "english"
              }
            },
            {
              "range": {
                "residents": {
                  "gt": 60000000
                }
              }
            }
          ]
        }
      }
    }
  }
}

Wenn wir nun die Query mit ODER verbinden, also wie die folgende SQL Query:

SELECT * FROM countries WHERE residents > 60000000 or language LIKE '%english%';

Dann würden wir erwarten alle Länder ausser Spanien zurückzubekommen, da jedes entweder mehr als 60000000 Einwohner hat, oder als Sprache english.

Da equivant zu ODER, ist should:

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "should": [
            {
              "match": {
                "language": "english"
              }
            },
            {
              "range": {
                "residents": {
                  "gt": 60000000
                }
              }
            }
          ]
        }
      }
    }
  }
}

Die war eine erste Vertierung der elastic search query syntax. Ich wünsche viel Spass beim ausprobieren und entdecken von elastic search.

Navigation