Elasticsearch 的查询流程是一个分布式、多阶段的过程,旨在高效地从多个分片中检索数据并合并结果。以下是其核心步骤的详细解析
1. 客户端请求与协调节点(Coordinating Node)
-
请求入口:客户端向任意节点(通常是协调节点)发送查询请求(如
GET /index/_search)。 -
协调节点职责:
- 解析查询条件(如
query、filter、sort、aggregations)。 - 确定目标索引的分片分布(主分片和副本分片)。
- 将查询分发到相关分片(主分片或副本分片)所在的数据节点(Data Node) 。
- 解析查询条件(如
2. 分片级查询(Shard-Level Query)
每个数据节点独立执行本地分片的查询操作:
步骤一:Query Phase(查询阶段)
-
倒排索引检索:
- 根据查询条件(如
term、match)在分片的**倒排索引(Inverted Index)**中查找匹配的文档 ID。 - 若使用全文搜索,会经过分词(Tokenizer)和相关性评分(如 TF-IDF 或 BM25)。
- 根据查询条件(如
-
构建优先级队列:
- 每个分片返回前
size + from条文档的元数据(_id、_score、_source等),默认按相关性排序。 - 队列大小由
size(返回文档数)和from(偏移量)参数决定。
- 每个分片返回前
步骤二:Fetch Phase(获取阶段)
-
跨分片数据拉取:
- 协调节点汇总所有分片的优先级队列,重新排序后确定最终结果的文档 ID。
- 向对应分片发送
_mget请求,获取完整文档内容(_source)
3. 结果合并与返回
-
合并与排序:
- 协调节点对所有分片返回的文档进行全局排序(如按
_score降序)。 - 执行聚合操作(如
terms、avg)并生成最终统计结果。
- 协调节点对所有分片返回的文档进行全局排序(如按
-
响应返回:
- 返回包含匹配文档的 JSON 结果(默认前 10 条),以及元数据(
took、_shards、hits.total等)。
- 返回包含匹配文档的 JSON 结果(默认前 10 条),以及元数据(
4. 关键机制与优化
-
分布式搜索的两阶段模型
-
Query Then Fetch:
- 第一阶段(Query Phase)快速筛选候选文档,避免传输大量无效数据。
- 第二阶段(Fetch Phase)仅拉取最终需要的文档内容,减少网络开销。
-
-
分片路由与负载均衡
- 默认轮询选择分片副本(如主分片和副本分片交替使用),均衡查询负载。
- 可通过
preference参数指定优先查询主分片或特定节点。
-
缓存机制
- 分片请求缓存(Shard Request Cache) :缓存聚合结果和
size:0的查询。 - 节点查询缓存(Node Query Cache) :缓存常用过滤条件(如
term、range)的匹配结果。
- 分片请求缓存(Shard Request Cache) :缓存聚合结果和
-
搜索类型(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)及优化手段,是解决慢查询、提升搜索性能的关键。实际应用中需结合业务场景,权衡相关性、实时性与资源消耗。