Elasticsearch 的查询流程浅析

136 阅读3分钟

Elasticsearch 的查询流程是一个分布式、多阶段的过程,旨在高效地从多个分片中检索数据并合并结果。以下是其核心步骤的详细解析

1. 客户端请求与协调节点(Coordinating Node)

  • 请求入口:客户端向任意节点(通常是协调节点)发送查询请求(如 GET /index/_search)。

  • 协调节点职责

    • 解析查询条件(如 queryfiltersortaggregations)。
    • 确定目标索引的分片分布(主分片和副本分片)。
    • 将查询分发到相关分片(主分片或副本分片)所在的数据节点(Data Node)

2. 分片级查询(Shard-Level Query)

每个数据节点独立执行本地分片的查询操作:

步骤一:Query Phase(查询阶段)
  • 倒排索引检索

    • 根据查询条件(如 termmatch)在分片的**倒排索引(Inverted Index)**中查找匹配的文档 ID。
    • 若使用全文搜索,会经过分词(Tokenizer)和相关性评分(如 TF-IDF 或 BM25)。
  • 构建优先级队列

    • 每个分片返回前 size + from 条文档的元数据(_id_score_source 等),默认按相关性排序。
    • 队列大小由 size(返回文档数)和 from(偏移量)参数决定。
步骤二:Fetch Phase(获取阶段)
  • 跨分片数据拉取

    • 协调节点汇总所有分片的优先级队列,重新排序后确定最终结果的文档 ID。
    • 向对应分片发送 _mget 请求,获取完整文档内容(_source

3. 结果合并与返回

  • 合并与排序

    • 协调节点对所有分片返回的文档进行全局排序(如按 _score 降序)。
    • 执行聚合操作(如 termsavg)并生成最终统计结果。
  • 响应返回

    • 返回包含匹配文档的 JSON 结果(默认前 10 条),以及元数据(took_shardshits.total 等)。

4. 关键机制与优化

  1. 分布式搜索的两阶段模型

    • Query Then Fetch

      • 第一阶段(Query Phase)快速筛选候选文档,避免传输大量无效数据。
      • 第二阶段(Fetch Phase)仅拉取最终需要的文档内容,减少网络开销。
  2. 分片路由与负载均衡

    • 默认轮询选择分片副本(如主分片和副本分片交替使用),均衡查询负载。
    • 可通过 preference 参数指定优先查询主分片或特定节点。
  3. 缓存机制

    • 分片请求缓存(Shard Request Cache) :缓存聚合结果和 size:0 的查询。
    • 节点查询缓存(Node Query Cache) :缓存常用过滤条件(如 termrange)的匹配结果。
  4. 搜索类型(Search Type)

    • query_then_fetch(默认):适用于大多数场景。
    • dfs_query_then_fetch:在 Query Phase 前计算全局词频,提升相关性评分准确性(性能较低)。

5. 查询流程示意图

6. 常见性能优化建议

  • 避免深分页:使用 search_after 或滚动查询(Scroll API)替代 from + size
  • 合理使用过滤上下文:将不参与评分的条件放入 filter(如时间范围),利用缓存提升速度。
  • 限制返回字段:通过 _source 过滤减少数据传输量。
  • 合并索引:减少分片数量以降低分布式查询开销(需权衡写入性能)。

总结

Elasticsearch 的查询流程通过 分阶段处理、分布式并行计算、缓存机制 实现了高效检索。理解其核心步骤(Query Phase 和 Fetch Phase)及优化手段,是解决慢查询、提升搜索性能的关键。实际应用中需结合业务场景,权衡相关性、实时性与资源消耗。