Search code examples
elasticsearchelasticsearch-painless

Query_string in combination with function_score always gives score 1.0


When I am trying to make a query_string request to my Elasticsearch that uses a function_score (script_score) to manipulate its default score. But I always seem to get a base _score of 1.0.

My model looks like this:

{
    "name": "Secret Birthday Party",
    "description": "SECRET! Discuss with discretion",
    "_userCounters": [
        {
            "user": "king",
            "count": 12
        },
        {
            "user": "joseph",
            "count": 1
        }
    ]
}

My request with the function_score script looks like this:

    {
    "query" : {
        "function_score" : {
            "query": {
                "query_string": {
                    "query": "secret",
                    "analyze_wildcard": true,
                    "fields": [
                        "name", "description"
                    ]
                }
            },
            "script_score": {
                "script": {
                    "inline" : "int scoreBoost = 1; for (int i = 0; i < params['_source']['_userCounters'].length; i++) { if (params['_source']['_userCounters'][i].user == 'joseph') { scoreBoost += params['_source']['_userCounters'][i].count; } } return scoreBoost;"
                }
            }
        }
    }
}

What I am getting is a result which finds exactly what I want, but only returns the value from the function_score script. The built-in scoring does not seem to work anymore. This is the response I am getting:

{
    "_index": "test3",
    "_type": "projects",
    "_id": "7",
    "_score": 2, // this is exactly the return value of the script_score. What I want instead is that this value gets multiplied with the normal score of ES
    "_source": {
        "name": "Secret Birthday Party",
        "description": "SECRET! Discuss with discretion",
        "_userCounters": [
            {
                "user": "queen",
                "count": 12
            },
            {
                "user": "daniel",
                "count": 1
            }
        ]
    }
}

My guess is that my request body is not in the correct format since all scores are just 1.0 when I take the function_score out completely.


Solution

  • I figured it out. It was actually a problem with the script itself and not with the structure of the request body.

    The function was only returning the factor which is supposed to be multiplied with the _score value. Instead it needs to do the multiplication itself.

    Here is the script a bit more readibale:

    int scoreBoost = 1;
    
    for (int i = 0; i < params['_source']['_userData'].length; i++) {
    if (params['_source']['_userData'][i].user == '{userId}') {
            scoreBoost += params['_source']['_userData'][i].count;
        }
    }
    
    // the error was here: only the scoreBoost value was returned
    // the fix is to multiply it with the _score value
    return _score * scoreBoost;