Query ES per abbinare tutti gli elementi nell'array

Sep 29 2020

Quindi ho ottenuto questo documento con un array nidificato che voglio filtrare con questa query.

Voglio che ES restituisca tutti i documenti in cui tutti gli elementi hanno modifiche = 0 e solo quello. Se il documento ha anche un solo elemento nell'elenco con una modifica = 1, viene scartato.

C'è un modo per ottenerlo partendo dalla query che ho già scritto? O dovrei usare uno script invece?

DOCUMENTI:

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

DOMANDA:

GET trips_solutions/_search

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

RISULTATO ATTESO:

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

Versione Elasticsearch: 7.6.2

Ho già letto queste risposte ma non mi hanno aiutato: https://discuss.elastic.co/t/how-to-match-all-item-in-nested-array/163873 ElasticSearch: come interrogare un array nidificato esatto

Risposte

JoeSorocin Sep 29 2020 at 13:50

Prima di tutto, se filtri per id: abc, ovviamente non sarai in grado di tornare id: defindietro.

In secondo luogo, a causa della natura dei nestedcampi che sono trattati come documenti secondari separati, non è possibile interrogare per tutti quelli tripsche hanno changesuguale a 0 - la connessione tra i singoli viaggi è persa e loro "non si conoscono".

Quello che puoi fare è restituire solo i viaggi che corrispondono alla tua query nidificata utilizzando inner_hits:

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

La soluzione più semplice è quindi salvare dinamicamente queste informazioni nidificate su un oggetto genitore come discusso qui e utilizzando la query intervallo / termine sull'array risultante.


MODIFICARE:

Ecco come lo fai utilizzando copy_toil livello superiore del documento:

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

trips_changessarà un array di numeri - presumo che siano numeri interi ma sono disponibili più tipi .

Quindi sincronizzare alcuni documenti:

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}]}

E infine interrogando:

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"
            }
          }
        }
      ]
    }
  }
}

Si noti che per prima cosa filtriamo normalmente utilizzando il termine nidificato query per restringere il nostro contesto di ricerca (gli script sono lenti, quindi questo è utile). Quindi controlliamo se ci sono valori diversi da zero changesnelle modifiche di livello superiore accumulate e rifiutiamo quelle applicabili.