Elasticsearch – 二次打分处理方案

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

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

2、通过function_query来设置分数。

通过function_query来设置分数

线性提升

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

GET /blogposts/post/_search  
{  
  "query": {  
    "function_score": {  
      "query": {  
        "multi_match": {  
          "query":    "popularity",  
          "fields": [ "title", "content" ]  
        }  
      },  
      "field_value_factor": {  
        "field":    "votes",  
        "modifier": "log1p",  
        "factor":   2   
      }  
    }  
  }  
}  

其中:

  • 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通过什么运算来得出新分值。

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   
    }  
  }  
}  

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 英镑的度假屋,而且与距离相比, 我们的用户对价格更为敏感,这样查询可以写成:

{  
    "query": {  
        "function_score": {  
          "functions": [  
            {  
              "gauss": {  
                "price": {  
                  "origin": "0",  
                  "scale": "20"  
                }  
              }  
            },  
            {  
              "gauss": {  
                "location": {  
                  "origin": "11, 12",  
                  "scale": "2km"  
                }  
              }  
            }  
          ],  
          "query": {  
            "match": {  
              "properties": "balcony"  
            }  
          },  
          "score_mode": "multiply"  
        }  
    }  
}  

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

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

参考资料

原文地址:https://www.cnblogs.com/pzblog/p/9088447.html