Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Must match multiple values

I have a query that works fine when I need the property of a document to match just one value.

However I also need to be able to search with must with two values.

So if a banana has id 1 and a lemon has id 2 and I search for yellow I will get both if I have 1 and 2 in the must clause. But if i have just 1 I will only get the banana.

{
  "from": 0, 
  "size": 20,
  "query": {
  "bool": {
    "should": [
      { "match": 
        { "fruit.color":  "yellow" }}
    ],
    "must" : [ 
      { "match": { "fruit.id" : "1" } }
    ]
  }
 } 
}

I haven´t found a way to search with two values with must. is that possible?

like image 899
dontberude Avatar asked Feb 23 '16 17:02

dontberude


3 Answers

If the document "must" be returned only if the id is 1 or 2, that sounds like another should clause. If I'm understanding your question properly, you want documents with either id 1 OR id 2. Additionally, if the color is yellow, give it a higher score.

Here's one way you might achieve what you're looking for:

{
  "query": {
    "bool": {
      "should": {
        "match": {
          "fruit.color": "yellow"
        }
      },
      "must": {
        "bool": {
          "should": [
            {
              "match": {
                "fruit.id": "1"
              }
            },
            {
              "match": {
                "fruit.id": "2"
              }
            }
          ]
        }
      }
    }
  }
}

Here I put the two match queries in the should clause of a separate bool query. This achieves the OR behavior you are looking for.

Have another look at the Bool Query documentation and take note of the nuances of should. It behaves differently by default depending on whether or not there is a sibling must clause and whether or not the bool query is being executed in filter context.

Another key option that is adjustable and can help you achieve your expected results is the minimum_should_match parameter. Have a look at this documentation page.

like image 124
BrookeB Avatar answered Nov 10 '22 18:11

BrookeB


Instead of a match query, you could simply try the terms query for ORing between multiple terms.

Match queries are generally used for analyzed fields. For exact matching, you should use term queries

{
  "from": 0, 
  "size": 20,
  "query": {
    "bool": {
      "should": [
        { "match": { "fruit.color": "yellow" } }
      ],
      "must" : [ 
        { "terms": { "fruit.id": ["1","2"] } }
      ]
    }
  } 
}
like image 32
Rahul Avatar answered Nov 10 '22 16:11

Rahul


term or terms query is the perfect way to fetch the exact text or id, using match query result in search inside the id or text

Ex: id = '4' id = '44'

Search using match query with id = 4 return both 4 & 44 since it matches 4 in both. This is where terms query come into play. same search using terms query will return 4 only.

So the accepted is absolutely wrong. Use the @Rahul answer. Just one more thing you need to do, Instead of text you need to analyse the field as a keyword

Example for indexing a field both as a text and keyword (mapping is for flat level for nested change it accordingly).

{
    "index_patterns": [ "test" ],
    "mappings": {
        "kb_mapping_doc": {
            "_source": {
                "enabled": true
            },
            "properties": {
                "id": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword"
                        }
                    }
                }
            }
        }
    }
}

using @Rahul's answer doesn't worked because you might be analysed as a text.

  • id - access a text field
  • id.keyword - access a keyword field

it would be

{
    "from": 0,
    "size": 20,
    "query": {
        "bool": {
            "should": [{
                "match": {
                    "color": "yellow"
                }
            }],
            "must": [{
                "terms": {
                    "id.keyword": ["1", "2"]
                }
            }]
        }
    }
}

So I would say accepted answer will return falsy results Please use @Rahul's answer with the corresponding mapping.

like image 8
devansvd Avatar answered Nov 10 '22 16:11

devansvd