Search code examples
elasticsearchsearchelasticsearch-aggregation

elasticsearch - get intermediate scores within 'function_score'


Here's my index

POST /blogs/1
{
  "name" : "learn java", 
  "popularity" : 100
}

POST /blogs/2
{
  "name" : "learn elasticsearch", 
  "popularity" : 10
}

My search query:

GET /blogs/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "name": "learn"
        }
      },
      "script_score": {
        "script": {
          "source": "_score*(1+Math.log(1+doc['popularity'].value))"
        }
      }
    }
  }
}

which returns:

[
  {
    "_index": "blogs",
    "_type": "1",
    "_id": "AW5fxnperVbDy5wjSDBC",
    "_score": 0.58024323,
    "_source": {
      "name": "learn elastic search",
      "popularity": 100
    }
  },
  {
    "_index": "blogs",
    "_type": "1",
    "_id": "AW5fxqmL8cCMCxtBYOyC",
    "_score": 0.43638366,
    "_source": {
      "name": "learn java",
      "popularity": 10
    }
  }
]

Problem: I need to return an extra field in results which would give me raw score (just tf/idf which doesn't take popularity into account)

Things I have explored: script_fields (which doesn't give access to _score at fetch time.


Solution

  • The problem is in the way you are querying, which over-writes the _score variable. Instead if you use sort then _score isn't changed and can be pulled up within the same query.

    You can try querying this way :

    {
      "query": {
        "match": {
          "name": "learn"
        }
      },
      "sort": [
        {
          "_script": {
            "type": "number",
            "script": {
              "lang": "painless",
              "source": "_score*(1+Math.log(1+doc['popularity'].value))"
            },
            "order": "desc"
          }
        },
        "_score"
      ]
    }