Elasticsearch – 二次打分处理方案

有时ES默认的评分规则并不能满足需求,时长会有在old_source的基础上根据某字段的值需要重新打分的需求场景,比如在相关度相差不大的情况下时间越进越靠前,或者评论数越多越靠前等等。此时需要重新打分。对此可以通过两种方式法来处理:<!-- more -->

1、在创建索引的时候提高文档的权重,根据因素字段值来给文档设置boost.这种方式在lucene之前有效,之后就无效了。不建议采用。

2、通过function_query来设置分数。

通过function_query来设置分数

线性提升

如在相关度相差不大的情况下,投票的数量越多排名越往前。可以采用简单的线性方式来处理:

1GET /blogposts/post/_search 2{ 3 "query": { 4 "function_score": { 5 "query": { 6 "multi_match": { 7 "query": "popularity", 8 "fields": [ "title", "content" ] 9 } 10 }, 11 "field_value_factor": { 12 "field": "votes", 13 "modifier": "log1p", 14 "factor": 2 15 } 16 } 17 } 18}

其中:

  • field:表示影响权重的字段例子中是votes

  • modifier:表示影响的规则

  • 修饰语 modifier 的值可以为: none (默认状态) log 、 log1p 、 log2p 、 ln 、 ln1p 、 ln2p 、 square 、 sqrt 以及 reciprocal。 facror:表示影响因子。 通过上面设置后整个打分变为:

    new_score = old_score * log(1 + factor * number_of_votes)
    factor 值大于 1 会提升效果, factor 值小于 1 会降低效果。

初次之外还可以设置boost_mode影响因子和old_source通过什么运算来得出新分值。

1GET /blogposts/post/_search 2{ 3 "query": { 4 "function_score": { 5 "query": { 6 "multi_match": { 7 "query": "popularity", 8 "fields": [ "title", "content" ] 9 } 10 }, 11 "field_value_factor": { 12 "field": "votes", 13 "modifier": "log1p", 14 "factor": 0.1 15 }, 16 "boost_mode": "sum" , 17 "max_boost": 1.5 18 } 19 } 20}

boost_mode multiply评分 _score 与函数值的积(默认) sum评分 _score 与函数值的和 min评分 _score 与函数值间的较小值 max评分 _score 与函数值间的较大值 replace函数值替代评分 _scoremax_boost设置最大的得分分值 无论 field_value_factor 函数的结果如何,最终结果都不会大于 1.5

引入模型函数来控制二次评分

上线是一种线性的影响关系,有时会有范围性质、分数变化缓慢的需求场景,此时在使用上面的方案未免为使分数变化的不太圆滑,es提供了三种衰减函数(decay functions)来计算分数,让我们有能力在两个滑动标准如:地点和价格,时间等之间权衡。

   linear、 exp 和 gauss (线性、指数和高斯函数),它们可以操作数值、时间以及经纬度地理坐标点这样的字段。所有三个函数都能接受以下参数:

origin:中心点 或字段可能的最佳值,落在原点 origin 上的文档评分 _score 为满分 1.0 。 scale:衰减率,即一个文档从原点origin下落时,评分_score 改变的速度.(例如,每 £10 欧元或每 100 米) decay:从原点 origin 衰减到 scale 所得的评分 _score ,默认值为 0.5 。 offset:以原点 origin 为中心点,为其设置一个非零的偏移量 offset 覆盖一个范围,而不只是单个原点。在范围 -offset <= origin <= +offset 内的所有评分 _score 都是 1.0 。 这三个函数的唯一区别就是它们衰减曲线的形状,用图来说明会更为直观

图 33 “衰减函数曲线” 中所有曲线的原点 origin (即中心点)的值都是 40 , offset 是 5 ,也就是在范围 40 - 5 <= value <= 40 + 5 内的所有值都会被当作原点 origin 处理——所有这些点的评分都是满分 1.0 。

在此范围之外,评分开始衰减,衰减率由 scale 值(此例中的值为 5 )和 衰减值 decay (此例中为默认值 0.5 )共同决定。结果是所有三个曲线在 origin +/- (offset + scale) 处的评分都是 0.5 ,即点 30和 50 处。

linear 、 exp 和 gauss (线性、指数和高斯)函数三者之间的区别在于范围( origin +/- (offset + scale) )之外的曲线形状:

linear 线性函数是条直线,一旦直线与横轴 0 相交,所有其他值的评分都是 0.0 。 exp 指数函数是先剧烈衰减然后变缓。 gauss 高斯函数是钟形的——它的衰减速率是先缓慢,然后变快,最后又放缓。 选择曲线的依据完全由期望评分 _score 的衰减速率来决定,即距原点 origin 的值。

回到我们的例子:用户希望租一个离伦敦市中心近( { "lat": 51.50, "lon": 0.12} )且每晚不超过 £100 英镑的度假屋,而且与距离相比, 我们的用户对价格更为敏感,这样查询可以写成:

1{ 2 "query": { 3 "function_score": { 4 "functions": [ 5 { 6 "gauss": { 7 "price": { 8 "origin": "0", 9 "scale": "20" 10 } 11 } 12 }, 13 { 14 "gauss": { 15 "location": { 16 "origin": "11, 12", 17 "scale": "2km" 18 } 19 } 20 } 21 ], 22 "query": { 23 "match": { 24 "properties": "balcony" 25 } 26 }, 27 "score_mode": "multiply" 28 } 29 } 30}

location 字段以地理坐标点 geo_point 映射。 price 字段是数值。 price 语句是 location 语句权重的两倍。 location 语句可以简单理解为: 以伦敦市中作为原点 origin 。 所有距原点 origin 2km 范围内的位置的评分是 1.0 。 距中心 5km ( offset + scale )的位置的评分是 0.5 。

weight 参数可以被用来调整每个语句的贡献度,权重 weight 的默认值是 1.0 。这个值会先与每个句子的评分相乘,然后再通过 score_mode 的设置方式合并。

参考资料

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Python之time模块的时间戳、时间字符串格式化与转换

Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y

Twitter的分布式自增ID算法snowflake (Java版)

概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移