Search code examples
elasticsearch-mappingelasticsearch-7

How to associate a value with a keyword in Elasticsearch


I am using Elasticsearch 7.6 and indexing a list of keywords with the following mapping definition:

"keywords" : {
  "type" : "text",
  "analyzer": "std_folded",
  "store": true,
  "fields": {
    "keyword": {
      "type": "keyword"
    }
  }
},

As you can see, the name of the field is keywords which will be given a list of words. Also, I defined keywords.keyword as the keyword type.

Is it possible to assign some value (a score) with each word? I am hoping to retrieve the value in my script query later.


Solution

  • Background

    So if it was not with each word but to assign a specific value(score as in your case)for each field, you could have used something similar to index-time boost which is deprecated from 5.0.

    If I understood, you can have multiple values for your keywords field like foo, bar and baz belongs to the same document. and you want to give all of the different scores like foo:1, bar:2 and baz:3, that's the score or boost on-field value, not on the field.

    Solution: using nested data-type you can solve this.

    Working example:

    Index def

    {
      "mappings": {
        "properties": {
          "keywords": {
            "type": "nested" --> note this
          }
        }
      }
    }
    

    Index sample doc

    {
      "keywords" : [
        {
          "keyword" : "foo",
          "score" :  1
        },
        {
          "keyword" : "bar",
          "score" :  2
        },
        {
            "keyword" : "baz",
            "score" : 3
        }
      ]
    }
    

    Search query to fetch docs having foo and score 1

    {
        "query": {
            "nested": {
                "path": "keywords",
                "query": {
                    "bool": {
                        "must": [
                            {
                                "match": {
                                    "keywords.keyword": "foo"
                                }
                            },
                            {
                                "match": {
                                    "keywords.score": 1
                                }
                            }
                        ]
                    }
                },
                "inner_hits": { --> notice this, it would bring inner doc `foo:1`
    
                }
            }
        }
    }
    

    Search result

     "hits": [
          {
            "_index": "nested",
            "_type": "_doc",
            "_id": "1",
            "_score": 1.9808291,
            "_source": {
              "keywords": [
                {
                  "keyword": "foo",
                  "score": 1
                },
                {
                  "keyword": "bar",
                  "score": 2
                },
                {
                  "keyword": "baz",
                  "score": 3
                }
              ]
            },
            "inner_hits": {
              "keywords": {
                "hits": {
                  "total": {
                    "value": 1,
                    "relation": "eq"
                  },
                  "max_score": 1.9808291,
                  "hits": [
                    {
                      "_index": "nested",
                      "_type": "_doc",
                      "_id": "1",
                      "_nested": {
                        "field": "keywords",
                        "offset": 0
                      },
                      "_score": 1.9808291, --> your expected result in inner hits
                      "_source": {
                        "keyword": "foo",
                        "score": 1
                      }
                    }
                  ]