Zelf
Zelf

Reputation: 2290

Elasticsearch nested filter query

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.

Upvotes: 1

Views: 2027

Answers (1)

Sloan Ahrens
Sloan Ahrens

Reputation: 8718

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

Upvotes: 3

Related Questions