本章翻译自Elasticsearch官方指南的Controlling Relevance一章。html
function_score查询是处理分值计算过程的终极工具。它让你可以对全部匹配了主查询的每份文档调用一个函数来调整甚至是彻底替换原来的_score。git
实际上,你能够经过设置过滤器来将查询获得的结果分红若干个子集,而后对每一个子集使用不一样的函数。这样你就可以同时得益于:高效的分值计算以及可缓存的过滤器。github
它拥有几种预先定义好了的函数:json
weight缓存
对每份文档适用一个简单的提高,且该提高不会被归约:当weight为2时,结果为2 * _score。dom
field_value_factorelasticsearch
使用文档中某个字段的值来改变_score,好比将受欢迎程度或者投票数量考虑在内。ide
random_score函数
使用一致性随机分值计算来对每一个用户采用不一样的结果排序方式,对相同用户仍然使用相同的排序方式。工具
衰减函数(Decay Function) - linear,exp,gauss
将像publish_date,geo_location或者price这类浮动值考虑到_score中,偏好最近发布的文档,邻近于某个地理位置(译注:其中的某个字段)的文档或者价格(译注:其中的某个字段)靠近某一点的文档。
script_score
使用自定义的脚原本彻底控制分值计算逻辑。若是你须要以上预约义函数以外的功能,能够根据须要经过脚本进行实现。
没有function_score查询的话,咱们也许就不能将全文搜索获得分值和近因进行结合了。咱们将不得不根据_score或者date进行排序;不管采用哪种都会抹去另外一种的影响。function_score查询让咱们可以将二者融合在一块儿:仍然经过全文相关度排序,可是给新近发布的文档,或者流行的文档,或者符合用户价格指望的文档额外的权重。你能够想象,一个拥有全部这些功能的查询看起来会至关复杂。咱们从一个简单的例子开始,按部就班地对它进行介绍。
假设咱们有一个博客网站让用户投票选择他们喜欢的文章。咱们但愿让人气高的文章出如今结果列表的头部,可是主要的排序依据仍然是全文搜索分值。咱们能够经过保存每篇文章的投票数量来实现:
PUT /blogposts/post/1
{
"title": "About popularity", "content": "In this post we will talk about...", "votes": 6 }
在搜索期间,使用带有field_value_factor函数的function_score查询将投票数和全文相关度分值结合起来:
GET /blogposts/post/_search
{
"query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes" } } } }
function_score查询会包含主查询(Main Query)和但愿适用的函数。先会执行主查询,而后再为匹配的文档调用相应的函数。每份文档中都必须有一个votes字段用来保证function_score可以起做用。
在前面的例子中,每份文档的最终_score会经过下面的方式改变:
new_score = old_score * number_of_votes
它获得的结果并很差。全文搜索的_score一般会在0到10之间。而从下图咱们能够发现,拥有10票的文章的分值大大超过了这个范围,而没有被投票的文章的分值会被重置为0。
modifier
为了让votes值对最终分值的影响更缓和,咱们可使用modifier。换言之,咱们须要让头几票的效果更明显,其后的票的影响逐渐减少。0票和1票的区别应该比10票和11票的区别要大的多。
一个用于此场景的典型modifier是log1p,它将公式改为这样:
new_score = old_score * log(1 + number_of_votes)
log函数将votes字段的效果减缓了,其效果相似下面的曲线:
使用了modifier参数的请求以下:
GET /blogposts/post/_search
{
"query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p" } } } }
可用的modifiers有:none(默认值),log,log1p,log2p,ln,ln1p,ln2p,square,sqrt以及reciprocal。它们的详细功能和用法能够参考field_value_factor文档。
factor
能够经过将votes字段的值乘以某个数值来增长该字段的影响力,这个数值被称为factor:
GET /blogposts/post/_search
{
"query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p", "factor": 2 } } } }
添加了factor将公式修改为这样:
new_score = old_score * log(1 + factor * number_of_votes)
当factor大于1时,会增长其影响力,而小于1的factor则相应减少了其影响力,以下图所示:
boost_mode
将全文搜索的相关度分值乘以field_value_factor函数的结果,对最终分值的影响可能太大了。经过boost_mode参数,咱们能够控制函数的结果应该如何与_score结合在一块儿,该参数接受下面的值:
若是咱们是经过将函数结果累加来获得_score,其影响会小的多,特别是当咱们使用了一个较低的factor时:
GET /blogposts/post/_search
{
"query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p", "factor": 0.1 }, "boost_mode": "sum" } } }
上述请求的公式以下所示:
new_score = old_score + log(1 + 0.1 * number_of_votes)
max_boost
最后,咱们可以经过制定max_boost参数来限制函数的最大影响:
GET /blogposts/post/_search
{
"query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p", "factor": 0.1 }, "boost_mode": "sum", "max_boost": 1.5 } } }
不管field_value_factor函数的结果是多少,它毫不会大于1.5。
NOTE
max_boost只是对函数的结果有所限制,并非最终的_score。