reikje
reikje

Reputation: 3064

How to write a boolean query in Elasticsearch that does a field1 AND (field2 OR field3)

I have an index that contains three string fields "user_id", "headline" and "note". I want to search for documents that A) belong to a specific user and B) have a text match in either the "headline" or "notes". I am using AWS Elasticsearch 7.4 and I haven't done any schema or mapping - I simply started to post documents against the index.

What I tried was this:

          query = {
                "bool": {
                    "should": [
                        {"match": {"headline": search_text}},
                        {"match": {"note": search_text}}
                    ],
                    "must": {"match": {"user_id": user_id}}
                }
            } 

This works but it finds documents where search text does not match either "headline" or "note". Basically I need a boolean query saying: user_id = :user_id AND (headline = :search_text OR note = :search_text)

Upvotes: 2

Views: 198

Answers (2)

Amit
Amit

Reputation: 32386

Due to in-proper use of boolean clause your existing query not working and its working according to Refer https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html for more details on boolean query

user_id = :user_id OR (headline = :search_text OR note = :search_text)

Complete working example tested in my local with sample docs:

Indexed three sample docs with defining mapping:

{
  "user_id" : "1",
  "headline" : "today",
  "note" : "today"
}


{
  "user_id" : "1",
  "headline" : "tomorrow",
  "note" : "today"
}

{
  "user_id" : "1",
  "headline" : "tomorrow",
  "note" : "tomorrow"
}

According to your condition, when searching for user_id 1 and text = today only doc 1 and 2 must be returned.

Proper search query

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "user_id": "1"
          }
        },
        {
          "multi_match": {
            "query": "today",
            "fields": [
              "headline",
              "note"
            ]
          }
        }
      ]
    }
  }
}

Search result

 "hits": [
      {
        "_index": "booleanaws",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.1143606,
        "_source": {
          "user_id": "1",
          "headline": "today",
          "note": "today"
        }
      },
      {
        "_index": "booleanaws",
        "_type": "_doc",
        "_id": "2",
        "_score": 0.603535,
        "_source": {
          "user_id": "1",
          "headline": "tomorrow",
          "note": "today"
        }
      }
    ]

Upvotes: 2

Rahul Singh
Rahul Singh

Reputation: 710

The following query should work for : user_id = :user_id AND (headline = :search_text OR note = :search_text)

query = {
            "bool": {
                must:[
                {
                 "match": {"user_id": user_id}
                },
                "bool":{
                  "should":[
                      {"match": {"headline": search_text}},
                      {"match": {"note": search_text}}
                  ]  
                }
              ]
            }
        }

Upvotes: 0

Related Questions