Frage Kombinierte nicht geschachtelte und geschachtelte Abfrage in Elasticsearch


Ich möchte ES für eine Buchsuche verwenden. Also habe ich beschlossen, den Autorennamen und Titel (als verschachteltes Dokument) wie folgt in den Index zu schreiben:

curl -XPUT localhost:9200/library/search_books/1 -d'{
  "author": "one",
  "books": [
    {
      "title": "two",
    },
    {
      "title": "three",
    }
  ]
}'

Was ich nicht bekomme, ist: Wie muss ich die Suchabfrage strukturieren, um nur Buch zwei zu finden, wenn ich nach "eins zwei" suche und nichts finde, wenn ich nach "zwei drei" suche und alle Bücher, wenn ich nach "eins" suche?


17
2018-03-22 18:32


Ursprung


Antworten:


Vielleicht so etwas?

{
  "query":{
    "bool":{
      "must":[
        {
          "term":{
            "author":"one"
          }
        },
        {
          "nested":{
            "path":"books",
            "query":{
              "term":{
                "books.title":"two"
              }
            }
          }
        }
      ]
    }
  }
}

Diese Abfrage besagt grundsätzlich, dass ein Dokument Muss haben muss author: one und books.title: two. Sie können diese Abfrage problemlos neu konfigurieren. Wenn Sie beispielsweise nur nach Autoren suchen möchten, entfernen Sie den verschachtelten Teil. Wenn Sie ein anderes Buch wünschen, ändern Sie das verschachtelte usw.

Dies setzt voraus, dass Sie das tatsächliche verwenden Verschachtelte Dokumenteund nicht innere Objekte. Für innere Objekte können Sie nur vollständig qualifizierte Pfade ohne die spezielle verschachtelte Abfrage verwenden.

Bearbeiten1: Sie könnten dies vielleicht mit einer geschickten Erhöhung zur Indexzeit erreichen, obwohl es nur eine ungefähre Lösung sein wird. Wenn "Autor" stark erhöht wird, wird es höher als Übereinstimmungen mit nur dem Titel sortiert, selbst wenn der Titel mit beiden Teilen der Abfrage übereinstimmt. Sie könnten dann einen min_score-Cutoff verwenden, um zu verhindern, dass diese angezeigt werden.

Es ist nur eine lockere Annäherung, da einige durchkriechen können. Es kann auch komische Dinge zur allgemeinen Sortierung zwischen "richtigen" Übereinstimmungen machen.

Edit2:  Mit query_string aktualisiert, um eine "single input" -Option verfügbar zu machen:


{
  "query":{
    "query_string" : {
      "query" : "+author:one +books.title:two"
    }
  }
}

Dies setzt voraus, dass Sie Standard-Innenobjekte verwenden. Wenn Sie echte verschachtelte Typen haben, wird der query_string sehr viel komplexer:


{
  "query":{
    "query_string" : {
      "query" : "+author:one +BlockJoinQuery (filtered(books.title:two)->cache(_type:__books))"
    }
  }
}

Sehr großer Haftungsausschluss Ich habe keinen dieser beiden query_strings getestet, daher sind sie möglicherweise nicht genau richtig. Aber sie zeigen, dass die Lucene-Syntax nicht allzu freundlich ist.


Edit3 - Das ist meine beste Idee:

Nachdem Sie darüber nachgedacht haben, könnte Ihre beste Lösung darin bestehen, ein spezielles Feld zu indizieren, das den Autor und den Buchtitel verkettet. Etwas wie das:

{
  "author": "one",
  "books": [
    {
      "title": "two",
    },
    {
      "title": "three",
    }
  ],
  "author_book": [ "one two", "one three" ]
}

In der Suchzeit können Sie dann exakte Term-Übereinstimmungen aktivieren author_book:

{
  "query" : {
    "term" : {
      "author_book" : "one two"
    }
  }
}

15
2018-03-22 23:47



Ich habe die Antwort in diesem Post gefunden: Spaß mit Elasticsearch's Children und Nested Documents. Ein verschachteltes Dokument ist der Schlüssel. Die Zuordnung:

{
  "book":{
    "properties": {
      "tags": { "type": "multi_field",
        "fields": {
            "tags": { "type": "string", "store":"yes", "index": "analyzed" },
            "facet": { "type": "string", "store":"yes", "index": "not_analyzed" }
        }
      },
      "editions": { "type": "nested", 
        "properties": {
          "title_author": { "type": "string", "store": "yes", "index": "analyzed" },
          "title": { "type": "string", "store": "yes", "index": "analyzed" }
        }
      }
    }
  }
}

Das Dokument:

"tags": ["novel", "crime"],
  "editions": [
    {
      "title": "two",
      "title_author": "two one"
    },
    {
      "title": "three",
      "title_author": "three one"
    }
  ]

Jetzt kann ich suchen wie:

{

  "query": {
    "bool": {
      "should": [
        {
          "nested": {
            "path": "editions",
            "query": {
              "match": {
                "editions.title_author": {
                  "query": "one two",
                  "operator": "and"
                }
              }
            }
          }
        }
      ]
    }
  }
}

Und wenn nach "zwei drei" gesucht würde, würde ich kein Match bekommen. Ich würde eins mit "eins zwei" oder "eins drei" bekommen. In Version 1.1.0 gibt es eine weitere Option mit einer multi_match-Abfrage und der Option cross_fields, die es ermöglichen würde, den Titel nicht zu wiederholen und nur den Autorennamen zu jedem verschachtelten Dokument hinzuzufügen. Das würde den Index kleiner halten.


4
2018-03-07 14:51