简介

Function score 查询
https://www.elastic.co/guide/en/elasticsearch/reference/7.3/query-dsl-function-score-query.html#query-dsl-function-score-query

可以在查询结束后,对每一个匹配的文档进行一系列的重新算分,根据新生成的分数进行排序。

在使用ES进行全文搜索时,搜索结果默认会以文档的相关度进行排序,而这个 “文档的相关度”,是可以 通过 function_score 自己定义的,也就是说我们可以通过使用function_score,来控制 “怎样的文档相 关度得分更高” 这件事。

  1. # random代表随机, 随机范围在0-5之间生成, 可以让文档随机显示
  2. GET /book/_search
  3. {
  4. "query": {
  5. "function_score": {
  6. "query": {
  7. "match_all": {}
  8. },
  9. "boost": "5",
  10. "random_score": {}
  11. }
  12. }
  13. }

比如对 book 进行随机打分 如果没有给函数提供过滤,则等效于指定”match_all”:{}
要排除不符合特定分数阈值的文档,可以将min_score参数设置为所需分数阈值。

为了使min_score正常工作,需要对查询返回的所有文档进行评分,然后逐一过滤掉。

function_score
查询提供了几种类型的得分函数。

  • script_score: 自定义脚本完全控制所需逻辑
  • weight: 为每一个文档设置一个简单而不被规范化的权重
  • random_score: 为每一个用户使用一个不同的,随机算分结果
  • fieldvalue_factor: 使用该数值来修改 score,例如将“热度”和“点赞数”作为算分的参考因素
  • decay functions: gauss, linear, exp 以某个字段的值为标准,距离某个值越近,得分越高

Field Value factor

可以使用文档中的字段来影响得分。与使用 script_score 函数类似,但是它避免了脚本编写的开销。如果用于多值字段,则在计算中仅使用该字段的第一个值

  1. GET /book/_search
  2. {
  3. "query": {
  4. "function_score": {
  5. "field_value_factor": {
  6. "field": "price",
  7. "factor": 1.2,
  8. "modifier": "sqrt"
  9. }
  10. }
  11. }
  12. }

它将转化为以下得分公式 sqrt(1.2 * doc[‘price’].value)

field_value_factor函数有许多选项:

属性 说明
field 要从文档中提取的字段
factor 字段值乘以的值,默认为1
modifier 应用于字段值的修饰符可以是以下之一: none , log ln2p , square , sqrt , or reciprocal 。默认为无

modifier 的取值
image.png

field_value_score函数产生的分数必须为非负数,否则将引发错误。如果在0到1之间的值上使用 log和ln修饰符将产生负值。请确保使用范围过滤器限制该字段的值以避免这种情况,或者使用 log1p 和 ln1p

random_score

随着运营团队的辛苦劳作,在线书店的用户量上来了,现在想给用户推荐一些书籍。我们当然可以上线一个推荐系统,但这个明显不是现阶段需要做的事情,我们需要尽量简单地完成这个需求。
为了满足给用户推荐书籍的需求,可以使用 random_score 算分函数来实现。需要为每一个用户推荐随机的数据,但是希望一段时间内同一个用户访问的时候,这部分内容的排序都是一样的。
random_score 算分函数的使用示例:

  1. POST books/_search
  2. {
  3. "query": {
  4. "function_score": {
  5. "random_score": {
  6. "seed": 81819,
  7. "field": "_seq_no"
  8. }
  9. }
  10. }
  11. }

如上示例,当 seed 的值不变的时候,随机内容的排序结果将不会变化。需要注意的是,在使用 random_score 算分函数的时候,需要指定 seed 和 field,如果只指定 seed,需要在 _id 字段上加载 fielddata,这样将会消耗大量的内存
一般来说,使用 “_seq_no” 作为 field 的值是比较推荐的,但是如果 seed 不变的情况下,文档被更新了,这个时候文档的 _seq_no 是会变化的,将会导致排序结果的变化。