Elasticsearch nested filter query

2k views Asked by At

Here's an example of my json document I'm trying to create a query against. The "params" field is mapped as "nested".

{
   "images": [
      {
         "name": "1907183375555f7c44126f23.67610475.png"
      },
      {
         "name": "5693836375575c567764bc2.87695507.png"
      }
   ],
   "sku": "MYSKU",
   "class": "some_class",
   "params": [
      {
         "name": "item1",
         "value": "item1value"
      },
      {
         "name": "item2",
         "value": "item2value"
      },
      {
         "name": "item3",
         "value": "item3value"
      },
      {
         "name": "item4",
         "value": "item4value"
      },
      {
         "name": "item5",
         "value": "item5value"
      }
   ]
}

How do I create a filtered query that will search on the sku, class, and nested params? E.g. in pseudocode, I would have a "bool" "must" on the sku and class, and then a "nested" "filter" "bool" "must" on each of the params that make up the document. At https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-filter.html I can see how one would use nested on a document where each nested field was a unique field name, but in my document each array element has "name" and "value".

Seems like this should be simple.

1

There are 1 answers

2
Sloan Ahrens On BEST ANSWER

This ought to do it (for example):

POST /test_index/_search
{
   "query": {
      "filtered": {
         "query": {
            "match_all": {}
         },
         "filter": {
            "bool": {
               "must": [
                  {
                     "term": {
                        "class": "some_class"
                     }
                  },
                  {
                     "term": {
                        "sku": "MYSKU1"
                     }
                  },
                  {
                     "nested": {
                        "path": "params",
                        "filter": {
                           "term": {
                              "params.name": "item1"
                           }
                        }
                     }
                  },
                  {
                     "nested": {
                        "path": "params",
                        "filter": {
                           "term": {
                              "params.name": "item3"
                           }
                        }
                     }
                  }
               ]
            }
         }
      }
   }
}

Note that there are separate nested filter clauses for each nested doc that you want to match (I only included two, but you could include as many as you want); if instead we used a bool inside a single nested clause, with a bunch of filters inside the inner bool, ES would try to find a single nested doc that matched all the supplied filters. This way we are telling ES that the nested filters don't have to all apply to the same nested document.

Here's the code I used to test it:

http://sense.qbox.io/gist/26552d6a8a285c7715b0ac4feab08bd283971664