Search code examples
elasticsearchelasticsearch-painless

access query value from function_score to compute new score


I need to customize ES score. The score function I need to implement is:

score = len(document_term) - len(query_term)

For instance, one of my document in the ES index is :

{
  "name": "foobar"
}

And the search query

{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "name": {
            "query": "foo"
          }
        }
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "source": "doc['name'].value.length() - ?LEN(query_tem)?"
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  }
}

The above search should provide a score of 6 - 3 = 3. But I didn't find a solution to get access the value of the query term.

Is it possible to access the value of the query term in a function_score context ?


Solution

  • There is no direct way to do this, however you can achieve that in the below way where you would need to add the query parameters in two different parts of the query.

    Before that one important note, you cannot apply the doc['myfield'].value if the field is of type text, instead you would need to have its sibling field created as keyword and refer that in the script, which again I've mentioned below:

    Mapping:

    PUT myindex
    {
      "mappings" : {
        "properties" : {
          "myfield" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
    

    Sample Document:

    POST myquery/_doc/1
    {
      "myfield": "I've become comfortably numb"
    }
    

    Query:

    POST <your_index_name>/_search
    {
      "query": {
        "function_score": {
          "query": {
            "match": {
              "myfield": "numb"
            } 
          },
          "functions": [
            {
              "script_score": {
                "script": {
                  "source": "return doc['myfield.keyword'].value.length() - params.myquery.length()",
                  "params": {
                    "myquery": "numb"          <---- Add the query string here as well
                  }
                }
              }
            }
          ],
          "boost_mode": "replace"
        }
      }
    }
    

    Response:

    {
      "took" : 558,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 24.0,
        "hits" : [
          {
            "_index" : "myindex",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 24.0,
            "_source" : {
              "myfield" : "I've become comfortably numb"
            }
          }
        ]
      }
    }
    

    Hope this helps!