简体   繁体   中英

How to do an exact match query in ElasticSearch?

I want to do an exact match query to an ElasticSearch index,
I have the following data -

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.21110919,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.21110919,
        "_source" : {
          "id" : 1,
          "name" : "test"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.160443,
        "_source" : {
          "id" : 2,
          "name" : "test two"
        }
      }
    ]
  }
}

I want to query the field name ,
I am trying to search the name test ,
But it returns me both documents.

The expected result is the only document 1 .
Mapping is as follows -

{
  "test" : {
    "mappings" : {
      "properties" : {
        "id" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

I tried the following -

GET /test/_search
{
  "query": {
    "bool": {
      "must": {
        "term" : { 
          "name": "test"
        }
      }
    }
  }
}


GET /test/_search
{
  "query": {
    "match": {
      "name": "test"
    }
  }
}

Looks like you are using text datatype on your name field, which is spitting test two in 2 tokens as test and two , hence it matches your search query test as match query is analyzed and applies the same analyzer to resultant tokens are matched against the documents tokens present in the inverted index.

Solution your using example

Index def

{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword" --> note use of `keyword` type
      }
    }
  }
}

Index you sample docs

{
   "name" : "test two"
}

{
   "name" : "test"
}

Search query same as yours

{
    "query": {
        "match": {
            "name": "test"
        }
    }
}

Search results as you want

"hits": [
         {
            "_index": "so_key",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.6931471,
            "_source": {
               "name": "test"
            }
         }
      ]

Important Note: you can use the analyze API to see how your data is indexed, for example

Using standard(default analyzer) on the text field

POST _analyze

{
    "text": "test two",
    "analyzer" : "standard" --> Change analyzer to keyword and see diff
}

Tokens

{
    "tokens": [
        {
            "token": "test",
            "start_offset": 0,
            "end_offset": 4,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "two",
            "start_offset": 5,
            "end_offset": 8,
            "type": "<ALPHANUM>",
            "position": 1
        }
    ]
}

In addition to the link to the answer I provided in comment, I would suggest you to define name field as:

{
   "name":{
      "type": "text",
      "fields":{
         "keyword":{
            "type": "keyword"
         }
      }
   }
}

and then query on field name.keyword whenever you require exact match (case sensitive) and name if you want partial match such as search on first name only.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM