galdikas
galdikas

Reputation: 1669

Find exact match phrase in ElasticSearch

So I have the following ElasticSearch query:

"query": {
"bool": {
  "must": [
    {
      "nested": {
        "path": "specs",
        "query": {
          "bool": {
            "must": [
              {
                "match": {
                  "specs.battery": "2 hours"
                }
              }
            ],
            "minimum_should_match": 1
          }
        }
      }
    },
    {
      "terms": {
        "category_ids": [
          16405
        ]
      }
    }
  ]
}
}

At the moment it returns all documents that have either 2 or hours in specs.battery value. How could I modify this query, so that it only returns documents, that have exact phrase 2 hours in specs.battery field? As well, I would like to have the ability to have multiple phrases (2hrs, 2hours, 3 hours etc etc). Is this achievable?

Upvotes: 2

Views: 2897

Answers (1)

isaac.hazan
isaac.hazan

Reputation: 3874

The data in elasticsearch is by default tokenized when you index it. This means the result of indexing the expression "2 hours" will be 2 tokens mapped to the same document. However there will not be a one token "2 hours", therefore it will either search 2 or hours or even will not find it if you use a filtered query.

To have Elasticseach consider "2 hours" as one expression you need to define specs.battery as not_analyzedin your mapping like follows:

curl -XPOST localhost:9200/your_index -d '{
    "mappings" : {
        "your_index_type" : {
            "properties" : {
                ...
                "battery" : { "type" : "string", "index":"not_analyzed" }
                ...
            }
        }
    }
}'

Then you can have an exact match using a filtered query as follows:

curl -XGET 'http://localhost:9200/_all/_search?pretty=true' -d '
{
    "query": {
        "filtered" : {
            "filter" : {        
                "term": {
                    "battery": "2 hours"
        }
       }
     }
    }
}'

Then you'll have an exact match.

More details at: https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_exact_values.html

If on the other hand you absolutely need your field to be analyzed or work with an existing index that you can't change, you still have a solution by using the operator "and" like follows:

curl -XGET localhost:9200/your_index'  -d '
{
    "query": {
        "match": {
           "battery": {
            "query": "2 hours",
            "operator": "and"
        }
    }
  }
}'

In the last option, you may have understood already that if you have a document that has "2 hours and something else" , the document will still be matched so this is not as precise as with an "not_analyzed" field.

More details on the last topic at:

https://www.elastic.co/guide/en/elasticsearch/guide/current/match-multi-word.html

Upvotes: 4

Related Questions