[Elasticsearch] 控制相关度 (五) - function_score查询及field_value_factor,boost_mode,max_...

news/2024/7/1 13:05:44

本章翻译自Elasticsearch官方指南的Controlling Relevance一章。

 

 

function_score查询

function_score查询是处理分值计算过程的终极工具。它让你能够对所有匹配了主查询的每份文档调用一个函数来调整甚至是完全替换原来的_score。

实际上,你可以通过设置过滤器来将查询得到的结果分成若干个子集,然后对每个子集使用不同的函数。这样你就能够同时得益于:高效的分值计算以及可缓存的过滤器。

它拥有几种预先定义好了的函数:

weight

对每份文档适用一个简单的提升,且该提升不会被归约:当weight为2时,结果为2 * _score。

field_value_factor

使用文档中某个字段的值来改变_score,比如将受欢迎程度或者投票数量考虑在内。

random_score

使用一致性随机分值计算来对每个用户采用不同的结果排序方式,对相同用户仍然使用相同的排序方式。

衰减函数(Decay Function) - linear,exp,gauss

将像publish_date,geo_location或者price这类浮动值考虑到_score中,偏好最近发布的文档,邻近于某个地理位置(译注:其中的某个字段)的文档或者价格(译注:其中的某个字段)靠近某一点的文档。

script_score

使用自定义的脚本来完全控制分值计算逻辑。如果你需要以上预定义函数之外的功能,可以根据需要通过脚本进行实现。

没有function_score查询的话,我们也许就不能将全文搜索得到分值和近因进行结合了。我们将不得不根据_score或者date进行排序;无论采用哪一种都会抹去另一种的影响。function_score查询让我们能够将两者融合在一起:仍然通过全文相关度排序,但是给新近发布的文档,或者流行的文档,或者符合用户价格期望的文档额外的权重。你可以想象,一个拥有所有这些功能的查询看起来会相当复杂。我们从一个简单的例子开始,循序渐进地对它进行介绍。

 

 

根据人气来提升(Boosting by Popularity)

假设我们有一个博客网站让用户投票选择他们喜欢的文章。我们希望让人气高的文章出现在结果列表的头部,但是主要的排序依据仍然是全文搜索分值。我们可以通过保存每篇文章的投票数量来实现:

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结合在一起,该参数接受下面的值:

  • multiply:_score乘以函数结果(默认情况)
  • sum:_score加上函数结果
  • min:_score和函数结果的较小值
  • max:_score和函数结果的较大值
  • replace:将_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。

http://blog.csdn.net/dm_vincent/article/details/42201721


http://www.niftyadmin.cn/n/3301784.html

相关文章

2013百度校园招聘数据挖掘工程师

2013百度校园招聘数据挖掘工程师 一、简答题(30分) 1、简述数据库操作的步骤(10分) 步骤:建立数据库连接、打开数据库连接、建立数据库命令、运行数据库命令、保存数据库命令、关闭数据库连接。 经萍萍提醒&#xff0c…

VC++ 创建及调用Dll

一、_stdcall 被这个关键字修饰的函数,其参数都是从右向左通过堆栈传递的(__fastcall 的前面部分由ecx,edx传), 函数调用在返回前要由被调用者清理堆栈。 这个关键字主要见于Microsoft Visual C、C。GNU的C、C是另外一种修饰方式:__attribut…

GYM 101102 J.Divisible Numbers(数论+容斥原理)

Description 给出一个长度为n的序列,q次查询,每次查询给出区间[l,r]和一个数s,s的二进制从右往左第i位表示i是否出现,统计[l,r]中有多少数可以被s所表示的这些出现的某一个数整除 Input 第一行一整数T表示用例组数,…

H5_0018:z-index失效的原因

在做的过程中,发现了一个很简单却又很多人应该碰到的问题,设置Z-INDEX属性无效。 在CSS中,只能通过代码改变层级,这个属性就是z-index, 要让z-index起作用有个小小前提,就是元素的position属性要是relative…

GYM 101102 K.Topological Sort(线段树)

Description 给出一个n个点的图,初始状态i点会向所有编号大于它的点连边,之后删去m条边,求删边之后涂的字典序最小的拓扑序 Input 第一行一整数T表示用例组数,每组用例首先输入两个整数n和m分别表示点数和要删除的边数&#xf…

软件测试和软件调试的区别

最近替客户写论文,整理提纲的时候发现他们把软件的测试和调试的部分分开写,虽然知道两者有区别但是当时根本搞不清楚应该怎么写,网上找了些资料看了以后才有些概念,现在贴出来,以后可那能用的到. 1,软件测试是找出软件已经存在的错误,而调试是定位错误,修改程序以修正错误. 2,…

总结工作中用到的ES6语法,方便工作中查看,也总结一下经验

1.模板字符串: 表现形式:${} 举例子: import axios from axios;let base https://www.baidu.com/home/msg/data/personalcontent; console.log(${base}/login,${base}/login) export const requestLogin params > { return axios.post($…

VS2008安装失败原因总结

今天系统是刚装的,今儿个也不是第一次装系统,也不是第一次装vs2008了,遇上vs2008安装出错倒是头一回。 先装系统,接着装0ffice2007,接着装ms sqlserver 2005,再装adobe cs4 master套装,一路setup,很是顺利&…