Home > OS >  Query with And & OR in Elastic Search
Query with And & OR in Elastic Search

Time:10-04

I'm new to Elastic Search, I have document like below :

Mapping of same JSON index is like below :

Mapping

{
      "mappings": {
        "properties": {
          "age": {
            "type": "long"
          },
          "hobbiles": {
            "type": "keyword"
          }
        
      }
    }
}

Some sample documents are like below :

        [{
        "_id": "[email protected]",
        "age": 12,
        "hobbiles": [{
                "name": "Singing",
                "level": "begineer"
            },
            {
                "name": "Dancing",
                "level": "begineer"
            }
        ]
    },
    {
        "_id": "[email protected]",
        "age": 7,
        "hobbiles": [{
                "name": "Coding",
                "level": "begineer"
            },
            {
                "name": "Chess",
                "level": "begineer"
            }
        ]
    },
    {
        "_id": "[email protected]",
        "age": 20,
        "hobbiles": [{
                "name": "Singing",
                "level": "begineer"
            },
            {
                "name": "Dancing",
                "level": "begineer"
            }
        ]
    },
    {
        "_id": "[email protected]",
        "age": 21,
        "hobbiles": [{
                "name": "Coding",
                "level": "begineer"
            },
            {
                "name": "Dancing",
                "level": "Football"
            }
        ]
    }
]

 

Now I want to fetch documents where id IN ([email protected], [email protected]) and age is greater than 5. [operationally] hobiiles Football.

My expectations from output is I should get three documents: and if hobbies is not matching then also it should be fine but if hobbies matches then that document should be on top. Basically I want to match hobbies but its optional if it doesn't match then also I should get data based on prior clauses.

[[email protected], [email protected], [email protected]]

test3 on top because Football matches there, and test and test1 because age and id matches there.

CodePudding user response:

This requires using Should clause. Should is equivalent to "OR". So a document will be returned if it satisfies any one condition in should query.

For conditions on id and age I have used filter clause. It is equivalent to "AND" . Filter clause does not calculate score for matched documents so any document which matches "hobbiles.level" will be ranked higher.

Query

{
  "query": {
    "bool": {
      "minimum_should_match": 1, 
      "should": [
        {
          "term": {
            "hobbiles.level.keyword": {
              "value": "Football"
            }
          }
        },
        {
          "bool": {
            "filter": [
              {
                "terms": {
                  "id.keyword": [
                    "[email protected]",
                    "[email protected]"
                  ]
                }
              },
              {
                "range": {
                  "age": {
                    "gt": 5
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Result

  "hits" : [
      {
        "_index" : "index8",
        "_type" : "_doc",
        "_id" : "qE06noMBfFiM6spcUTo4",
        "_score" : 1.3112575,
        "_source" : {
          "id" : "[email protected]",
          "age" : 21,
          "hobbiles" : [
            {
              "name" : "Coding",
              "level" : "begineer"
            },
            {
              "name" : "Dancing",
              "level" : "Football"
            }
          ]
        }
      },
      {
        "_index" : "index8",
        "_type" : "_doc",
        "_id" : "pE03noMBfFiM6spc4jr2",
        "_score" : 0.0,
        "_source" : {
          "id" : "[email protected]",
          "age" : 12,
          "hobbiles" : [
            {
              "name" : "Singing",
              "level" : "begineer"
            },
            {
              "name" : "Dancing",
              "level" : "begineer"
            }
          ]
        }
      },
      {
        "_index" : "index8",
        "_type" : "_doc",
        "_id" : "pU03noMBfFiM6spc6DqZ",
        "_score" : 0.0,
        "_source" : {
          "id" : "[email protected]",
          "age" : 7,
          "hobbiles" : [
            {
              "name" : "Coding",
              "level" : "begineer"
            },
            {
              "name" : "Chess",
              "level" : "begineer"
            }
          ]
        }
      }
    ]

CodePudding user response:

Tldr;

It can be achieved via bool queries.

Solution

PUT /_bulk
{"index":{"_index":"73935795", "_id":"[email protected]"}}
{"age":12,"hobbiles":[{"name":"Singing","level":"begineer"},{"name":"Dancing","level":"begineer"}]}
{"index":{"_index":"73935795", "_id":"[email protected]"}}
{"age":7,"hobbiles":[{"name":"Coding","level":"begineer"},{"name":"Chess","level":"begineer"}]}
{"index":{"_index":"73935795", "_id":"[email protected]"}}
{"age":20,"hobbiles":[{"name":"Singing","level":"begineer"},{"name":"Dancing","level":"begineer"}]}
{"index":{"_index":"73935795", "_id":"[email protected]"}}
{"age":21,"hobbiles":[{"name":"Coding","level":"begineer"},{"name":"Dancing","level":"Football"}]}

GET 73935795/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "age": {
              "gt": 5
            }
          }
        },
        {
          "terms": {
            "_id": [
              "[email protected]",
              "[email protected]"
            ]
          }
        }
      ],
      "should": [
        {
          "match": {
            "hobbiles.level": "football"
          }
        }
      ]
    }
  }
}
  • Related