SAM
SAM

Reputation: 661

Elasticsearch match an exact word in a field of type array

I have consulted few articles and stackoverflow questions but I am afraid I wasn't able to find anything like my scenario, forgive me if its duplicate.

Problem: I want to match a word "Tennis" to a filed which has an array of sports ["Football", "Tennis", "Table Tennis", "Basketball"]. Now the word should be an exact match.

Mapping:

            "properties": {
                "clubname": {
                    "type": "text"
                },
                "sports": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    }
                }
            }

DOC:

// DOC1
{
   "clubname": "Arena 51",
   "sports: ["Cricket","Football", "Tennis"]
}
// DOC2
{
   "clubname": "Play You",
   "sports: ["Cricket","Football", "Table Tennis"]
}

Query:

"query": {
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": [                
                {
                    "match": {
                        "sports": "tennis"
                    }
                }
            ]
        }
    }

With this query I get both documents, which I believe is correct behaviour. So how do I make elastic search to return only Doc1 when I search just Tennis

Upvotes: 3

Views: 891

Answers (2)

Bhavya
Bhavya

Reputation: 16172

The answer given by @Opster works fine if you search for Tennis, but if you want to have case insensitive search, you need to create custom normalization for index in the following way:

Index Mapping:

{
  "settings": {
    "analysis": {
      "normalizer": {
        "lowercase_normalizer": {
          "type": "custom",
          "char_filter": [],
          "filter": [
            "lowercase",
            "asciifolding"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "sports": {
        "type": "keyword",
        "normalizer": "lowercase_normalizer"
      }
    }
  }
}

Search query:

{
    "query": {
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": [                
                {
                    "match": {
                        "sports": "tennis"
                    }
                }
            ]
        }
    }
}

Search Result:

"hits": [
      {
        "_index": "fd_cb2",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "clubname": "Arena 51",
          "sports": [
            "Cricket",
            "Football",
            "Tennis"
          ]
        }
      }
    ]

Upvotes: 1

Nishant
Nishant

Reputation: 7864

For exact match you can use keyword sub-field:

{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": [
        {
          "term": {
            "sports.keyword": "Tennis"
          }
        }
      ]
    }
  }
}

Note that this will be case sensitive.

Upvotes: 1

Related Questions