Lucene 相关度评分
ES 底层基于 Lucene 进行评分,公式如下:
其中:
- q:查询
- d:当前文档
- t:q 中的词条
- tf(t in d):词条 t 在文档 d 中的词频
- idf(t):词条t在整个索引中的逆文档频率(逆文档频率:在同一个索引中存在该词条的文档数的倒数)
词条在文档中出现的频率越高,得分越高。索引中存在该词条的文档越少,得分越高。
ES 搜索评分过程
ES 有两种搜索类型:QUERY_THEN_FETCH
和 DFS_QUERY_THEN_FETCH
。下面分别对两种类型搜索过程进行详细介绍。
QUERY_THEN_FETCH
ES 默认的搜索类型是QUERY_THEN_FETCH
,搜索流程分为 Query 和 Fetch 两个阶段。
Query 阶段:
- ES 收到客户端搜索请求后,会由协调节点将请求分发给对应索引的每个 Shard 上。
- 每个 Shard 的 Lucene 实例基于本地 Shard 内的 TF/IDF 统计信息,独立完成 Shard 内的索引匹配和打分,并根据打分结果完成单个 Shard 内的排序、分页。
- 每个 Shard 将排序分页后的结果集元数据(文档id和分数)返回给协调节点。
- 协调节点完成整体的汇总、排序和分页,筛选出最终确认返回的搜索结果。
Fetch 阶段:
- 协调节点根据筛选结果去对应 Shard 拉取完整的文档数据。
- 整合最终的结果返回给客户端。
QUERY_THEN_FETCH
查询可能存在的问题:在极端情况下,Shard 中的文档数差距较大,那么 IDF 在不同 Shard 中起到的作用会截然不同,从而影响单个 Shard 内打分汇总后的结果,导致全局打分汇总的结果与预期产生较大出入。
DFS_QUERY_THEN_FETCH
ES 另一种搜索类型是DFS_QUERY_THEN_FETCH
,DFS 在这里意思是分布式频率打分,其思想是提前向所有 Shard 进行全局的统计信息搜集,然后将这些统计信息随着查询分发到各个 Shard,让各个 Shard 在本地采用全局 TF/IDF 打分。
整个搜索流程分为预统计阶段、Query 阶段和 Fetch 阶段。
预统计阶段:
ES 在收到客户端搜索请求后,由协调阶段进行一次预统计工作,即向所有相关 Shard 搜集统计信息。
Query 阶段:
- 由协调节点整合所有统计信息,将全局的统计信息连同请求一起分发到对应索引的每个 Shard 上。
- 每个 Shard 的 Lucene 实例基于 TF/IDF 统计信息独立完成 Shard 内的索引匹配和打分,并根据打分结果完成单个 Shard 内的排序和分页。
- 每个 Shard 将排序分页后的结果集的元数据返回给协调节点。
- 协调节点完成整体的汇总、排序和分页,筛选出最终确认返回的搜索结果。
Fetch 阶段:
- 协调节点根据筛选结果去对应 Shard 拉取完整的文档数据。
- 整合最终的结果返回给客户端。