ES query to match all elements in array

后端 未结 1 1934
轮回少年
轮回少年 2021-01-28 20:55

So I got this document with a nested array that I want to filter with this query.

I want ES to return all documents where all items have changes = 0 and that only. If doc

相关标签:
1条回答
  • 2021-01-28 21:13

    First off, if you filter by id: abc, you obviously won't be able to get id: def back.

    Second, due to the nature of nested fields which are treated as separate subdocuments, you cannot query for all trips that have the changes equal to 0 -- the connection between the individual trips is lost and they "don't know about each other".

    What you can do is return only the trips that matched your nested query using inner_hits:

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

    The easiest solution then is to dynamically save this nested info on a parent object like discussed here and using range/term query on the resulting array.


    EDIT:

    Here's how you do it using copy_to onto the doc's top level:

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

    trips_changes will be an array of numbers -- I presume they're integers but more types are available.

    Then syncing a few docs:

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

    And finally querying:

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

    Note that we first filter normally using the nested term query to narrow down our search context (scripts are slow so this is useful). We then check if there are any non-zero changes in the accumulated top-level changes and reject those that apply.

    0 讨论(0)
提交回复
热议问题