【ES】搜索原理

Lucene 相关度评分

ES 底层基于 Lucene 进行评分,公式如下:

其中:

  • q:查询
  • d:当前文档
  • t:q 中的词条
  • tf(t in d):词条 t 在文档 d 中的词频
  • idf(t):词条t在整个索引中的逆文档频率(逆文档频率:在同一个索引中存在该词条的文档数的倒数)

词条在文档中出现的频率越高,得分越高。索引中存在该词条的文档越少,得分越高。

ES 搜索评分过程

ES 有两种搜索类型:QUERY_THEN_FETCHDFS_QUERY_THEN_FETCH。下面分别对两种类型搜索过程进行详细介绍。

QUERY_THEN_FETCH

ES 默认的搜索类型是QUERY_THEN_FETCH,搜索流程分为 Query 和 Fetch 两个阶段。

Query 阶段:

  1. ES 收到客户端搜索请求后,会由协调节点将请求分发给对应索引的每个 Shard 上。
  2. 每个 Shard 的 Lucene 实例基于本地 Shard 内的 TF/IDF 统计信息,独立完成 Shard 内的索引匹配和打分,并根据打分结果完成单个 Shard 内的排序、分页。
  3. 每个 Shard 将排序分页后的结果集元数据(文档id和分数)返回给协调节点。
  4. 协调节点完成整体的汇总、排序和分页,筛选出最终确认返回的搜索结果。

Fetch 阶段:

  1. 协调节点根据筛选结果去对应 Shard 拉取完整的文档数据。
  2. 整合最终的结果返回给客户端。

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 阶段:

  1. 由协调节点整合所有统计信息,将全局的统计信息连同请求一起分发到对应索引的每个 Shard 上。
  2. 每个 Shard 的 Lucene 实例基于 TF/IDF 统计信息独立完成 Shard 内的索引匹配和打分,并根据打分结果完成单个 Shard 内的排序和分页。
  3. 每个 Shard 将排序分页后的结果集的元数据返回给协调节点。
  4. 协调节点完成整体的汇总、排序和分页,筛选出最终确认返回的搜索结果。

Fetch 阶段:

  1. 协调节点根据筛选结果去对应 Shard 拉取完整的文档数据。
  2. 整合最终的结果返回给客户端。