Search document with empty array field, on ElasticSearch

Kamafeather picture Kamafeather · Nov 4, 2014 · Viewed 23.3k times · Source

I have a set of documents (type 'article') and I want to search for the document that have elements/objects into an array field

{
    "_type": "article",
    "_source": {
        "title": "Article 1",
        "locations": [
            {
                "address": "ES headquarter",
                "city": "Berlin"
            }
        ]
    }
}

I want two queries (just one, but with a little variation):

  • get all the articles that have locations
  • get all the articles that have NO locations

I tried different things but probably I'm too bad with ElasticSearch:

{
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": [
        {
          "type": {
            "value": "article"
          }
        },
        {
          "bool": {
            "must_not": {
              "missing": {
                "field": "location",
                "existence": true,
                "null_value": true
              }
            }
          }
        }
      ]
    }
  }
}

this doesn't work.

  • How would you fix my query?

but mainly:

  • How would you perform this search for documents with a field that is an empty array?

Answer

Zoltan Balogh picture Zoltan Balogh · Nov 4, 2014

If address is a mandatory field in location array you can modify your query:

"must_not": {
  "missing": {
    "field": "locations.address"
  }
}

AFAIK, in ES you cannot query non-leaf elements (like your location field) (see issue), and in case object types ES flattens the nested fields (see nested type, object type). That's why I suggested to query for one of the leaf elements instead. But it requires that one of them is mandatory (which is unfortunately not satisfied in your case).

Anyway I found the solution using the _source parameter inside the source_filtering:

"must_not": {
  "script": {
    "script": "_source.locations.size() > 0"
  }
}

Note that using "lang":"groovy" you should write: "script": "_source.locations.size > 0"