How to create custom score boost functions in Elastic Search Module

To write your own custom score boost function just override GetQuery method in ElasticSearchRequestBuilder like this:

    public class ElasticSearchRequestBuilder2 : ElasticSearchRequestBuilder
    {
        public ElasticSearchRequestBuilder2(IElasticSearchFiltersBuilder searchFiltersBuilder, IElasticSearchAggregationsBuilder searchAggregationsBuilder, ISettingsManager settingsManager) : base(searchFiltersBuilder, searchAggregationsBuilder, settingsManager)
        {
        }

        protected override Query GetQuery(VirtoCommerceSearchRequest request)
        {
            var baseQuery = base.GetQuery(request);

            if (request.Take == 0)
            {
                return baseQuery;
            }

            return new FunctionScoreQuery()
            {
                Query = baseQuery,
                BoostMode = FunctionBoostMode.Replace,
                ScoreMode = FunctionScoreMode.Sum,

                Functions = new List<FunctionScore>
                {
                    new ScriptScoreFunction
                    {
                        Script = new Script(new InlineScript()
                        {
                            Source = "doc['ranktuning'].size()!=0 ? doc['ranktuning'].value * _score : _score"
                        })
                    }
                }
            };
        }
    }

And then register the new search builder class in Module Initialize :

serviceCollection.AddSingleton<IElasticSearchRequestBuilder, ElasticSearchRequestBuilder2>();

In this example the function multiplies original document score by the special int “ranktuning“ dynamic property value:

To access document field value in the function code use: doc['fieldname'].value

To check if field is in the document (an error will be thrown if not): doc['fieldname'].size()!=0

The function declaration will be translated into a ES query similar to:

{
    "query": {
        "function_score": {
            "boost_mode": "replace",
            "functions": [
                {
                    "script_score": {
                        "script": {
                            "source": "doc[\u0027ranktuning\u0027].size()!=0 ? doc[\u0027ranktuning\u0027].value * _score : _score"
                        }
                    }
                }
            ],
            "query": {
                "multi_match": {
                    "analyzer": "standard",
                    "fields": [
                        "__content"
                    ],
                    "operator": "and",
                    "query": "test"
                }
            },
            "score_mode": "sum"
        }
    },
    "size": 20
}

We can see that the function code is passed into function_score query and the original query is wrapped within it.

1 Like