ES-Abfrage für alle Elemente im Array

Sep 29 2020

Also habe ich dieses Dokument mit einem verschachtelten Array erhalten, das ich mit dieser Abfrage filtern möchte.

Ich möchte, dass ES alle Dokumente zurückgibt, bei denen alle Elemente Änderungen = 0 haben, und das nur. Wenn das Dokument nur ein einzelnes Element in der Liste mit einer Änderung = 1 enthält, wird dieses verworfen.

Gibt es eine Möglichkeit, dies ausgehend von der Abfrage zu erreichen, die ich bereits geschrieben habe? Oder sollte ich stattdessen ein Skript verwenden?

UNTERLAGEN:

{
    "id": "abc",
    "_source" : {
        "trips" : [
            {
                "type" : "home",
                "changes" : 0
            },
            {
                "type" : "home",
                "changes" : 1
            }
        ]
    }
},
{
        "id": "def",
        "_source" : {
            "trips" : [
                {
                    "type" : "home",
                    "changes" : 0
                },
                {
                    "type" : "home",
                    "changes" : 0
                }
            ]
        }
    }

ABFRAGE:

GET trips_solutions/_search

    {
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "id": {
                  "value": "abc"
                }
              }
            },
            {
              "nested": {
                "path": "trips",
                "query": {
                  "range": {
                    "trips.changes": {
                      "gt": -1,
                      "lt": 1
                    }
                  }
                }
              }
            }
          ]
        }
      }
    }

ERWARTETES ERGEBNIS:

{
            "id": "def",
            "_source" : {
                "trips" : [
                    {
                        "type" : "home",
                        "changes" : 0
                    },
                    {
                        "type" : "home",
                        "changes" : 0
                    }
                ]
            }
        }

Elasticsearch-Version: 7.6.2

Lesen Sie diese Antworten bereits, aber sie haben mir nicht geholfen: https://discuss.elastic.co/t/how-to-match-all-item-in-nested-array/163873 ElasticSearch: Abfragen des exakten verschachtelten Arrays

Antworten

JoeSorocin Sep 29 2020 at 13:50

Zunächst einmal, wenn Sie nach filtern id: abc, werden Sie offensichtlich nicht in der Lage sein, id: defzurück zu kommen .

Zweitens können Sie aufgrund der Art der nestedFelder, die als separate Unterdokumente behandelt werden, nicht alle abfragen trips, die changesgleich 0 sind - die Verbindung zwischen den einzelnen Fahrten geht verloren und sie "wissen nichts voneinander".

Sie können nur die Fahrten zurückgeben, die Ihrer verschachtelten Abfrage entsprechen, und zwar mit inner_hits:

GET trips_solutions/_search
{
  "_source": "false",
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "inner_hits": {},
            "path": "trips",
            "query": {
              "term": {
                "trips.changes": {
                  "value": 0
                }
              }
            }
          }
        }
      ]
    }
  }
}

Die einfachste Lösung besteht dann darin, diese verschachtelten Informationen wie hier beschrieben dynamisch in einem übergeordneten Objekt zu speichern und eine Bereichs- / Termabfrage für das resultierende Array zu verwenden.


BEARBEITEN:

So machen Sie es copy_toauf der obersten Ebene des Dokuments:

PUT trips_solutions
{
  "mappings": {
    "properties": {
      "trips_changes": {
        "type": "integer"
      },
      "trips": {
        "type": "nested",
        "properties": {
          "changes": {
            "type": "integer",
            "copy_to": "trips_changes"
          }
        }
      }
    }
  }
}

trips_changeswird eine Reihe von Zahlen sein - ich nehme an, sie sind ganze Zahlen, aber es sind mehr Typen verfügbar .

Synchronisieren Sie dann einige Dokumente:

POST trips_solutions/_doc
{"trips":[{"type":"home","changes":0},{"type":"home","changes":1}]}

POST trips_solutions/_doc
{"trips":[{"type":"home","changes":0},{"type":"home","changes":0}]}

Und schließlich abfragen:

GET trips_solutions/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "trips",
            "query": {
              "term": {
                "trips.changes": {
                  "value": 0
                }
              }
            }
          }
        },
        {
          "script": {
            "script": {
              "source": "doc.trips_changes.stream().filter(val -> val != 0).count() == 0"
            }
          }
        }
      ]
    }
  }
}

Beachten Sie, dass wir zuerst normalerweise mit der Abfrage verschachtelter Begriffe filtern, um unseren Suchkontext einzugrenzen (Skripte sind langsam, daher ist dies nützlich). Wir prüfen dann, ob changesdie akkumulierten Änderungen der obersten Ebene ungleich Null sind, und lehnen diejenigen ab, die zutreffen.