Mike Quinlan
Mike Quinlan

Reputation: 2882

Elasticsearch query for all tags not matching a set of tags

I have an elasticsearch index with document mappings that look like:

{
  "properties": {
    "tags": {"type": "keyword"}
  }
}

where the document looks like

{
  "_source": {
    "tags": ["one", "two"]
  }
}

I am trying to query it in such a way that it will be excluded from the search results if (and only if) it has ALL of the tags submitted with the request.

Examples:

searched with tags ["one"]: included

searched with tags ["one", "three"]: included

searched with tags ["one", "two"]: excluded

searched with tags ["one", "two", "three"]: excluded

I'm having a hard time getting this to work with bool queries. The closest I have gotten is with this query:

{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": [
            {
              "bool": {
                "must_not": [{
                  "terms": {"tags": ["one", "two"]}
                }]
              }
            }
          ]
        }
      }
    }
  }
}

but it is still filtering out results when only one of the tags matches. i.e. if I only submit ["one"]. Any guidance on this would be greatly appreciated.

Upvotes: 0

Views: 801

Answers (2)

Mike Quinlan
Mike Quinlan

Reputation: 2882

Major thanks to @ESCoder for helping me figure this out. By his/her answer, I figured out that I need a terms_set query because it's based on the should logic. This looks like it works for my use case:

{
  "query": {
    "bool": {
      "must_not": {
        "terms_set": {
          "tags": {
            "terms": ["one", "two"],
            "minimum_should_match_script": {
              "source": "doc['tags'].length"
            }
          }
        }
      }
    }
  }
}

It calculates the should match for each specific doc in the index. So that it can make sure all of the submitted tags match.

Upvotes: 0

Bhavya
Bhavya

Reputation: 16192

You can use a combination of bool should clause. Try out this below query

{
  "query": {
    "bool": {
      "must_not": [
        {
          "bool": {
            "should": [
              {
                "match": {
                  "tags": "one"
                }
              },
              {
                "match": {
                  "tags": "two"
                }
              }
            ],
            "minimum_should_match": 2
          }
        }
      ]
    }
  }
}

The search result will be

"hits": [
      {
        "_index": "66033399",
        "_type": "_doc",
        "_id": "1",
        "_score": 0.0,
        "_source": {
          "tags": [
            "one"
          ]
        }
      },
      {
        "_index": "66033399",
        "_type": "_doc",
        "_id": "2",
        "_score": 0.0,
        "_source": {
          "tags": [
            "one",
            "three"
          ]
        }
      }
    ]

Upvotes: 1

Related Questions