tugberk
tugberk

Reputation: 58434

term and range filters together in an elasticsearch query

In my eleasticsearch index, I have two documents indexed as below:

POST dyn-props/item
{
    "name": "bar foo",
    "properties": [
        {
            "type": "foo",
            "value": 1.45
        },

        {
            "type": "bar",
            "value": 256.34
        },

        {
            "type": "foobar",
            "value": 43.43
        }
    ]
}

POST dyn-props/item
{
    "name": "foo bar",
    "properties": [
        {
            "type": "foo",
            "value": 33.34
        },

        {
            "type": "bar",
            "value": 22.23
        }
    ]
}

On this item type, I would like to query for items which have foo property whose value is greater than 10. I can filter the results down for items that has a property whose type is foo with the below query:

POST dyn-props/item/_search
{
   "query": {
      "filtered": {
         "query": {
            "match_all": {}
         },
         "filter": {
            "term": {
               "properties.type": "foo"
            }
         }
      }
   }
}

but I am not sure how I can apply the range filter for value. Any idea?

Edit:

Issuing the below query gives me the wrong results as expected:

POST dyn-props/item/_search
{
   "query": {
      "filtered": {
         "query": {
            "match_all": {}
         },
         "filter": {
           "bool": {
             "must": [
               {
                  "term": {
                     "properties.type": "foo"
                  }
               },

                {
                   "range": {
                      "properties.value": {
                        "gte" : 10
                      }
                   }
                }
             ]
           }
         }
      }
   }
}

The result:

{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": 1,
      "hits": [
         {
            "_index": "dyn-props",
            "_type": "item",
            "_id": "PetPVxwARLOcZqlv28xjpw",
            "_score": 1,
            "_source": {
               "name": "bar foo",
               "properties": [
                  {
                     "type": "foo",
                     "value": 1.45
                  },
                  {
                     "type": "bar",
                     "value": 256.34
                  },
                  {
                     "type": "foobar",
                     "value": 43.43
                  }
               ]
            }
         },
         {
            "_index": "dyn-props",
            "_type": "item",
            "_id": "KqOTXcC9RG6FzPsDDDs8Hw",
            "_score": 1,
            "_source": {
               "name": "foo bar",
               "properties": [
                  {
                     "type": "foo",
                     "value": 33.34
                  },
                  {
                     "type": "bar",
                     "value": 22.23
                  }
               ]
            }
         }
      ]
   }
}

Upvotes: 3

Views: 5596

Answers (2)

tugberk
tugberk

Reputation: 58434

Found the answer. This post helped a lot: ElasticSearch – nested mappings and filters

Changed the mapping of the type:

PUT dyn-props
{
    "mappings": {
         "item": {
                "properties": {
                     "name": {
                            "type": "string"
                     },
                     "properties": {
                            "type": "nested"
                     }
                }
         }
    }
}

By making the properties as nested type, I was able to maintain the association between type and value fields.

Finally, I was able to issue the nested query for this:

POST dyn-props/item/_search
{
   "query": {
      "filtered": {
         "query": {
            "match_all": {}
         },
         "filter": {
            "nested": {
               "path": "properties",
               "filter": {
                  "bool": {
                     "must": [
                        {
                           "term": {
                              "type": "foo"
                           }
                        },
                        {
                           "range": {
                              "value": {
                                 "gte": 10
                              }
                           }
                        }
                     ]
                  }
               }
            }
         }
      }
   }
}

This got me the correct result:

{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "dyn-props",
            "_type": "item",
            "_id": "CzTL4sseR2GVYtvf-0slVQ",
            "_score": 1,
            "_source": {
               "name": "foo bar",
               "properties": [
                  {
                     "type": "foo",
                     "value": 33.34
                  },
                  {
                     "type": "bar",
                     "value": 22.23
                  }
               ]
            }
         }
      ]
   }
}

Upvotes: 5

Aliostad
Aliostad

Reputation: 81660

You have got to change the mapping of the index and change the type of the properties to nested.

This case has been explained in the docs: http://www.elasticsearch.org/blog/managing-relations-inside-elasticsearch/

Upvotes: 2

Related Questions