Approx 7 minutes read

I had a requirement where I needed to do exact match search in ElasticSearch. After searching a bit I landed to this page of ElasticSearch documentation. I was thrilled that I got the solution quickly (thanking god and ElasticSearch team in my mind). Hence I started testing by creating an index using request below:

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT localhost:9200/products/
{
  "mappings": {
    "product": {
      "properties": {
        "productName": {
          "type": "string",
          "index": "not_analyzed"
        }
      }
    }
  }
}

Then I added some data using request below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST localhost:9200/products/
{
  "productName": "Green Ball"
}

POST localhost:9200/products/
{
  "productName": "Red Ball"
}

POST localhost:9200/products/
{
  "productName": "Yellow Ball"
}

Now it was time for testing and hence I fired following request:

1
2
3
4
5
6
7
8
9
10
11
12
POST localhost:9200/products/product/_search
{
  "query":{
    "constant_score":{
      "filter":{
        "term":{
          "productName":"green ball"
        }
      }
    }
  }
}

And I was presented with following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "took":0,
  "timed_out":false,
  "_shards":{
    "total":5,
    "successful":5,
    "skipped":0,
    "failed":0
  },
  "hits":{
    "total":0,
    "max_score":null,
    "hits":[]
  }
}

I was surprised (and frustrated at the same time) as the data was there in ElasticSearch, still it was not returning the data. Soon enough I found that it was because the search was case sensitive and searching with “Green Ball” returned result. This was unacceptable in my use case as I needed case insensitive search. After searching a little bit more, I found that I have to create an analyzer with lowercase filter and use this to analyze the field on which I want to perform search. Hence I deleted the index and recreated it as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
DELETE localhost:9200/products/

PUT localhost:9200/products/
{
  "settings":{
    "index":{
      "analysis":{
        "analyzer":{
          "analyzer_case_insensitive":{
            "tokenizer":"keyword",
            "filter":"lowercase"
          }
        }
      }
    }
  },
  "mappings":{
    "product":{
      "properties":{
        "productName":{
          "type":"string",
          "analyzer":"analyzer_case_insensitive"
        }
      }
    }
  }
}

I needed to switch to match query as term query would return result with only lower case search text. Below is the modified query:

1
2
3
4
5
6
7
8
POST localhost:9200/products/product/_search
{
  "query":{
    "match":{
      "productName":"greeN ball"
    }
  }
}

And this resulted in following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "took":0,
  "timed_out":false,
  "_shards":{
    "total":5,
    "successful":5,
    "skipped":0,
    "failed":0
  },
  "hits":{
    "total":1,
    "max_score":0.6931472,
    "hits":[
      {
        "_index":"products",
        "_type":"product",
        "_id":"AV57L6vzqKOq3BnmUAzd",
        "_score":0.6931472,
        "_source":{
          "productName":"Green Ball"
        }
      }
    ]
  }
}

I was happy with the result as it served my purpose. Let me know in comments if there is a better way to achieve this.