越近越好

很多变量都可以影响用户对于度假屋的选择,也许用户希望离市中心近点,但如果价格足够便宜,也有可能选择一个更远的住处,也有可能反过来是正确的:愿意为最好的位置付更多的价钱。

如果我们添加过滤器排除所有市中心方圆 1 千米以外的度假屋,或排除所有每晚价格超过 £100 英镑的,我们可能会将用户愿意考虑妥协的那些选择排除在外。

function_score 查询会提供一组 衰减函数(decay functions) ,让我们有能力在两个滑动标准,如地点和价格,之间权衡。

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

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

这三个函数的唯一区别就是它们衰减曲线的形状,用图来说明会更为直观(参见 衰减函数曲线 )。

Figure 1. 衰减函数曲线

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

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

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

  • linear 线性函数是条直线,一旦直线与横轴 0 相交,所有其他值的评分都是 0.0
  • exp 指数函数是先剧烈衰减然后变缓。
  • gauss 高斯函数是钟形的——它的衰减速率是先缓慢,然后变快,最后又放缓。

选择曲线的依据完全由期望评分 _score 的衰减速率来决定,即距原点 origin 的值。

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

  1. GET /_search
  2. {
  3. "query": {
  4. "function_score": {
  5. "functions": [
  6. {
  7. "gauss": {
  8. "location": { (1)
  9. "origin": { "lat": 51.5, "lon": 0.12 },
  10. "offset": "2km",
  11. "scale": "3km"
  12. }
  13. }
  14. },
  15. {
  16. "gauss": {
  17. "price": { (2)
  18. "origin": "50", (3)
  19. "offset": "50",
  20. "scale": "20"
  21. }
  22. },
  23. "weight": 2 (4)
  24. }
  25. ]
  26. }
  27. }
  28. }

<1> location 字段以地理坐标点 geo_point 映射。

<2> price 字段是数值。

<3> 参见 理解价格语句 ,理解 origin 为什么是 50 而不是 100

<4> price 语句是 location 语句权重的两倍。

location 语句可以简单理解为:

  • 以伦敦市中作为原点 origin
  • 所有距原点 origin 2km 范围内的位置的评分是 1.0
  • 距中心 5kmoffset + scale )的位置的评分是 0.5

理解 price 价格语句

price 语句使用了一个小技巧:用户希望选择 £100 英镑以下的度假屋,但是例子中的原点被设置成 £50 英镑,价格不能为负,但肯定是越低越好,所以 £0 到 £100 英镑内的所有价格都认为是比较好的。

如果我们将原点 origin 被设置成 £100 英镑,那么低于 £100 英镑的度假屋的评分会变低,与其这样不如将原点 origin 和偏移量 offset 同时设置成 £50 英镑,这样就能使只有在价格高于 £100 英镑( origin + offset )时评分才会变低。

[TIP]

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