想搜索附近评分较高的餐厅,ElasticSearch 大显身手!

2年前 (2022) 程序员胖胖胖虎阿
200 0 0

松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->松哥要升级 SpringBoot 视频了,看看新增了哪些内容!


ElasticSearch 系列已经整到第 22 篇啦,今天我们来学习 Es 中的复合查询,前面已经和大家分享过一次复合查询了,今天我们来看看复合查询中的 function_score query 和 boosting query。

如果大家觉得视频风格还能接受,也可以看看松哥的付费视频:Spring Boot+Vue+微人事视频教程

以下是视频笔记:

注意,笔记只是视频内容的一个简要记录,因此笔记内容比较简单,完整的内容可以查看视频。

17.4 function_score query

场景:例如想要搜索附近的肯德基,搜索的关键字是肯德基,但是我希望能够将评分较高的肯德基优先展示出来。但是默认的评分策略是没有办法考虑到餐厅评分的,他只是考虑相关性,这个时候可以通过 function_score query 来实现。

准备两条测试数据:

PUT blog
{
  "mappings": {
    "properties": {
      "title":{
        "type""text",
        "analyzer""ik_max_word"
      },
      "votes":{
        "type""integer"
      }
    }
  }
}

PUT blog/_doc/1
{
  "title":"Java集合详解",
  "votes":100
}

PUT blog/_doc/2
{
  "title":"Java多线程详解,Java锁详解",
  "votes":10
}

现在搜索标题中包含 java 关键字的文档:

GET blog/_search
{
  "query": {
    "match": {
      "title""java"
    }
  }
}

查询结果如下:

想搜索附近评分较高的餐厅,ElasticSearch 大显身手!
image-20201117195614832

默认情况下,id 为 2 的记录得分较高,因为他的 title 中包含两个 java。

如果我们在查询中,希望能够充分考虑 votes 字段,将 votes 较高的文档优先展示,就可以通过 function_score 来实现。

具体的思路,就是在旧的得分基础上,根据 votes 的数值进行综合运算,重新得出一个新的评分。

具体有几种不同的计算方式:

  • weight
  • random_score
  • script_score
  • field_value_factor

weight

weight 可以对评分设置权重,就是在旧的评分基础上乘以 weight,他其实无法解决我们上面所说的问题。具体用法如下:

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "weight": 10
        }
      ]
    }
  }
}

查询结果如下:

想搜索附近评分较高的餐厅,ElasticSearch 大显身手!
image-20201117200243851

可以看到,此时的评分,在之前的评分基础上*10

random_score

random_score 会根据 uid 字段进行 hash 运算,生成分数,使用 random_score 时可以配置一个种子,如果不配置,默认使用当前时间。

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "random_score": {}
        }
      ]
    }
  }
}

script_score

自定义评分脚本。假设每个文档的最终得分是旧的分数加上votes。查询方式如下:

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "lang""painless",
              "source""_score + doc['votes'].value"
            }
          }
        }
      ]
    }
  }
}

现在,最终得分是 (oldScore+votes)*oldScore

如果不想乘以 oldScore,查询方式如下:

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "lang""painless",
              "source""_score + doc['votes'].value"
            }
          }
        }
      ],
      "boost_mode""replace"
    }
  }
}

通过 boost_mode 参数,可以设置最终的计算方式。该参数还有其他取值:

  • multiply:分数相乘
  • sum:分数相加
  • avg:求平均数
  • max:最大分
  • min:最小分
  • replace:不进行二次计算

field_value_factor

这个的功能类似于 script_score,但是不用自己写脚本。

假设每个文档的最终得分是旧的分数乘以votes。查询方式如下:

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field""votes"
          }
        }
      ]
    }
  }
}

默认的得分就是oldScore*votes

还可以利用 es 内置的函数进行一些更复杂的运算:

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field""votes",
            "modifier""sqrt"
          }
        }
      ],
      "boost_mode""replace"
    }
  }
}

此时,最终的得分是(sqrt(votes))。

modifier 中可以设置内置函数,其他的内置函数还有:

想搜索附近评分较高的餐厅,ElasticSearch 大显身手!

另外还有个参数 factor ,影响因子。字段值先乘以影响因子,然后再进行计算。以 sqrt 为例,计算方式为 sqrt(factor*votes)

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field""votes",
            "modifier""sqrt",
            "factor": 10
          }
        }
      ],
      "boost_mode""replace"
    }
  }
}

还有一个参数 max_boost,控制计算结果的范围:

GET blog/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "title""java"
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field""votes"
          }
        }
      ],
      "boost_mode""sum",
      "max_boost": 100
    }
  }
}

max_boost 参数表示 functions 模块中,最终的计算结果上限。如果超过上限,就按照上线计算。

17.5 boosting query

boosting query 中包含三部分:

  • positive:得分不变
  • negative:降低得分
  • negative_boost:降低的权重
GET books/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "name""java"
        }
      },
      "negative": {
        "match": {
          "name""2008"
        }
      },
      "negative_boost": 0.5
    }
  }
}

查询结果如下:

想搜索附近评分较高的餐厅,ElasticSearch 大显身手!
image-20201117205439025

可以看到,id 为 86 的文档满足条件,因此它的最终得分在旧的分数上*0.5

ElasticSearch 系列其他文章:

  1. 打算出一个 ElasticSearch 教程,谁赞成,谁反对?
  2. ElasticSearch 从安装开始
  3. ElasticSearch 第三弹,核心概念介绍
  4. ElasticSearch 中的中文分词器该怎么玩?
  5. ElasticSearch 索引基本操作
  6. ElasticSearch 文档的添加、获取以及更新
  7. ElasticSearch 文档的删除和批量操作
  8. ElasticSearch 文档路由,你的数据到底存在哪一个分片上?
  9. ElasticSearch 并发的处理方式:锁和版本控制
  10. ElasticSearch 中的倒排索引到底是什么?
  11. ElasticSearch 动态映射与静态映射
  12. ElasticSearch 四种字段类型详解
  13. ElasticSearch 中的地理类型和特殊类型
  14. ElasticSearch 23 种映射参数详解
  15. ElasticSearch 如何配置某个字段的权重?
  16. ElasticSearch 23 种映射参数详解【3】
  17. ElasticSearch 映射模版
  18. ElasticSearch 搜索入门
  19. ElasticSearch 全文搜索怎么玩?
  20. ElasticSearch 打错字还能搜索到?试试 fuzzy query!
  21. ElasticSearch 复合查询,理解 Es 中的文档评分策略!






往期推荐
0
1

50+ 需求文档免费下载!

0
2

Spring Security 教程合集

0
3

接了两个私活,都是血汗钱

想搜索附近评分较高的餐厅,ElasticSearch 大显身手!

本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

相关文章

暂无评论

暂无评论...