[Elasticsearch] 控制相关度 (五) - function_score查询及field_value_factor,boost_mode,max_mode参数

本章翻译自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。

时间: 2024-11-11 15:32:55

[Elasticsearch] 控制相关度 (五) - function_score查询及field_value_factor,boost_mode,max_mode参数的相关文章

[Elasticsearch] 控制相关度 (六) - function_score查询中的filter,functions及random_score参数

本章翻译自Elasticsearch官方指南的Looking at Time一章. 时间数据处理(Looking at Time) 如果在ES中,搜索是最常见的行为,那么创建日期柱状图(Date Histogram)肯定是第二常见的.为什么要使用日期柱状图呢? 想象在你的数据中有一个时间戳.数据是什么不重要-Apache日志事件,股票交易日期,棒球比赛时间-任何拥有时间戳的数据都能通过日期柱状图受益.当你有时间戳时,你经常会想创建基于时间的指标信息: 今年的每个月销售了多少辆车? 过去的12小时

[Elasticsearch] 控制相关度 (三) - 通过查询结构调整相关度以及boosting查询

本章翻译自Elasticsearch官方指南的Controlling Relevance一章. 通过查询结构调整相关度 ES提供的查询DSL是相当灵活的.你可以通过将单独的查询子句在查询层次中上下移动来让它更重要/更不重要.比如,下面的查询: quick OR brown OR red OR fox 我们可以使用一个bool查询,对所有词条一视同仁: GET /_search { "query": { "bool": { "should": [

[Elasticsearch] 控制相关度 (一) - 相关度分值计算背后的理论

本章翻译自Elasticsearch官方指南的Controlling Relevance一章. 控制相关度(Controlling Relevance) 对于仅处理结构化数据(比如日期,数值和字符枚举值)的数据库,它们只需要检查一份文档(在关系数据库中是一行)是否匹配查询即可. 尽管布尔类型的YES|NO匹配也是全文搜索的一个必要组成,它们本身是不够的.我们还需要知道每份文档和查询之间的相关程度.全文搜索引擎不仅要找到匹配的文档,还需要根据相关度对它们进行排序. 全文搜索相关度的公式,或者被称为

[Elasticsearch] 控制相关度 (四) - 忽略TF/IDF

本章翻译自Elasticsearch官方指南的Controlling Relevance一章. 忽略TF/IDF 有时我们不需要TF/IDF.我们想知道的只是一个特定的单词是否出现在了字段中.比如我们正在搜索度假酒店,希望它拥有的卖点越多越好: WiFi 花园(Garden) 泳池(Pool) 而关于度假酒店的文档类似下面这样: { "description": "A delightful four-bedroomed house with ... " } 可以使用

[Elasticsearch] 控制相关度 (二) - Lucene中的PSF(Practical Scoring Function)与查询期间提升

本章翻译自Elasticsearch官方指南的Controlling Relevance一章. Lucene中的Practical Scoring Function 对于多词条查询(Multiterm Queries),Lucene使用的是布尔模型(Boolean Model),TF/IDF以及向量空间模型(Vector Space Model)来将它们结合在一起,用来收集匹配的文档和对它们进行分值计算. 像下面这样的多词条查询: GET /my_index/doc/_search { "que

Elasticsearch入门教程(五):Elasticsearch查询(一)

原文:Elasticsearch入门教程(五):Elasticsearch查询(一) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/vbirdbest/article/details/79228852 // 准备数据 PUT /shop/goods/1 { "name": "2017新款女装冬季外套ulzzang棉袄中长款棉衣韩版百搭棉服面包服", &quo

[Elasticsearch] 全文搜索 (三) - match查询和bool查询的关系,提升查询子句

match查询是如何使用bool查询的 现在,你也许意识到了使用了match查询的多词查询只是简单地将生成的term查询包含在了一个bool查询中.通过默认的or操作符,每个term查询都以一个k语句被添加,所以至少一个should语句需要被匹配.以下两个查询是等价的: { "match": { "title": "brown fox"} } { "bool": { "should": [ { "

5. 蛤蟆的数据结构进阶五动态查询

5. 蛤蟆的数据结构进阶五动态查询 本篇名言:"判断一个人,不是根据他自己的表白或对自己的看法,而是根据他的行动. --列宁" OK,我们接下去来看下动态查询. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47284473 1.  动态查找表 动态查找表:若在查找过程中可以将查找表中不存在的数据元素插入,或者从查找表中删除某个数据元素,则称这类查找表为动态查找表.动态查找表在查找过程中查找表可能会发生变化.对动态

解决 Elasticsearch 超过 10000 条无法查询的问题

解决 Elasticsearch 超过 10000 条无法查询的问题 问题描述 分页查询场景,当查询记录数超过 10000 条时,会报错. 使用 Kibana 的 Dev Tools 工具查询 从第 10001 条到 10010 条数据. 查询语句如下: GET alarm/_search { "from": 10000, "size": 10 } 查询结果,截图如下: 报错信息如下: { "error": { "root_cause&