# Nested query with should clauses and filter

**URL:** <https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730>\
**Category:** Elasticsearch\
**Created:** [July 29, 2016, 12:59pm UTC](https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730 "2016-07-29T12:59:14Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jlp1](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/jlp1/32/6607_2.png) [@jlp1](https://discuss.elastic.co/u/jlp1)\
**Post date:** [July 29, 2016, 12:59pm UTC](https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730/1 "2016-07-29T12:59:14Z")

</div>

I am using nested query with should clauses in elasticsearch 2.3.2

```
GET shop/customer/_search
{
   "from": 0,
   "size": 25,
   "query": {
      "bool": {
         "must": [
            {
               "nested": {
                  "query": {
                     "bool": {
                        "should": [
                           {
                              "multi_match": {
                                 "query": "london",
                                 "fields": [
                                    "address.city",
                                    "address.street"
                                 ]
                              }
                           },
                           {
                              "term": {
                                 "address.postcode": "123"
                              }
                           }
                        ]                        
                     }
                  },
                  "path": "address"
               }
            }
         ]
      }
   }
}

```

It works fine but when I add a filter clause to the bool query - I expect this to return only a subset of previous results. However it returns more results - all documents with given address.type, ignoring the should clauses:

```
GET shop/customer/_search
{
   "from": 0,
   "size": 25,
   "query": {
      "bool": {
         "must": [
            {
               "nested": {
                  "query": {
                     "bool": {
                        "should": [
                           {
                              "multi_match": {
                                 "query": "london",
                                 "fields": [
                                    "address.city",
                                    "address.street"
                                 ]
                              }
                           },
                           {
                              "term": {
                                 "address.postcode": "123"
                              }
                           }
                        ],
                        "filter": [
                           {
                              "terms": {
                                 "address.type": [
                                    "4b4372b7"
                                 ]
                              }
                           }
                        ]
                     }
                  },
                  "path": "address"
               }
            }
         ]
      }
   }
}

```

I checked the same with not nested query and it works as I'd expected. The should queries return only documents that contains address and adding filter returns subset of this results matching filter.

---

<div class="post-metadata">

**Author:** ![polyfractal](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/polyfractal/32/48162_2.png) [@polyfractal](https://discuss.elastic.co/u/polyfractal)\
**Post date:** [July 29, 2016, 2:42pm UTC](https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730/2 "2016-07-29T14:42:13Z")

</div>

Yeah, this is a subtle issue due to how the new "filter" clause interacts with the bool.

So when you have all `"should"` clauses, one of them _must_ match (otherwise everything in the index would match, as they would all be optional). That's the situation your first query is in: all `"should"` clauses, so one of them _must_ match.

If you were to add a real `"must"` clause, the should's revert back to being entirely optional. Since the `"must"` _must_ match a document, all the optional clauses just exist for extra scoring purposes (they boost score if they match).

Now, the tricky bit: this also applies to the new `"filter"` clause. If you add a `"filter"`, the should's revert back to being entirely optional. So in your query's case, the only requirement is the "address.type", while the other clauses just exist to boost scoring. That's why you're seeing more matching hits.

The fix depends on what you want. Do you want the filter + one of the should clauses to match? If that's the case, you could do:

```auto
{
  "from":0,
  "size":25,
  "query":{
    "bool":{
      "must":[
        {
          "nested":{
            "query":{
              "bool":{
                "must":[
                  {
                    "bool":{
                      "should":[
                        {
                          "multi_match":{
                            "query":"london",
                            "fields":[
                              "address.city",
                              "address.street"
                            ]
                          }
                        },
                        {
                          "term":{
                            "address.postcode":"123"
                          }
                        }
                      ]
                    }
                  }
                ],
                "filter":[
                  {
                    "terms":{
                      "address.type":[
                        "4b4372b7"
                      ]
                    }
                  }
                ]
              }
            },
            "path":"address"
          }
        }
      ]
    }
  }
}

```

This put's the two should clauses inside their own bool, which is placed inside the must clause of the original bool. So this reads as: "The filter _must_ match AND one of the two should clauses _must_ match"

---

<div class="post-metadata">

**Author:** ![jlp1](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/jlp1/32/6607_2.png) [@jlp1](https://discuss.elastic.co/u/jlp1)\
**Post date:** [July 30, 2016, 7:20pm UTC](https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730/3 "2016-07-30T19:20:50Z")

</div>

Thanks, is the `minimum_should_match`=1 also correct in this case?

---

<div class="post-metadata">

**Author:** ![polyfractal](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/polyfractal/32/48162_2.png) [@polyfractal](https://discuss.elastic.co/u/polyfractal)\
**Post date:** [August 1, 2016, 1:42pm UTC](https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730/4 "2016-08-01T13:42:18Z")

</div>

Hah, oops. Yes, I think that would be the much simpler and more elegant solution 🙂

I'm about 95% sure that'll work, although give it a test to verify. Good call!

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [July 5, 2017, 10:31pm UTC](https://discuss.elastic.co/t/nested-query-with-should-clauses-and-filter/56730/5 "2017-07-05T22:31:12Z")

</div>


