Elasticsearch查询过程详解
Elasticsearch的一次查询过程如下所述,从客户端发送请求到最终返回结果的完整流程:
1. 客户端发送请求
客户端通过REST API向Elasticsearch集群发送查询请求。
2. 接收请求
接收查询的节点成为该请求的协调节点(Coordinating Node),负责管理整个查询过程。集群中的任何节点都可以作为协调节点。
3. 解析与验证
查询解析:
- 使用特定的解析器将JSON查询转换为抽象语法树(AST)
- 应用Elasticsearch的Query DSL解析器处理复杂查询
- 将查询字符串解析为Lucene查询对象
验证过程:
- 检查字段名是否存在于映射(mapping)中
- 验证字段类型与查询操作的兼容性
- 检查查询语法和参数的有效性
- 处理字段别名和多字段映射
4. 查询重写与优化
Elasticsearch分析并优化查询以提高性能。
5. 确定目标分片
索引路由:
- 协调节点查询集群状态(cluster state)获取索引的分片分配情况
- 对于默认路由,使用公式:
shard_num = hash(_routing) % num_primary_shards _routing默认为文档ID,也可自定义路由值
分片选择逻辑:
- 协调节点从集群状态元数据中获取分片分配信息
- 考虑索引别名和索引模式(index patterns)
- 应用索引路由规则确定具体分片
主/副本分片选择:
- 基于
preference参数选择分片(如_local、_primary或自定义值) - 考虑节点负载和分片健康状态
- 使用轮询(round-robin)策略在可用副本间分配查询
6. 查询分发
节点选择:
- 协调节点通过集群状态查找哪些节点托管所需分片
- 使用内部通信层(Transport Layer)建立到目标节点的连接
- 应用节点属性过滤(如冷/热节点分离策略)
请求分发:
- 协调节点构建TransportSearchAction请求
- 序列化查询并通过TCP发送到目标节点
- 设置请求超时和优先级信息
7. 分片级查询执行
分片内部结构:
-
每个分片包含多个Lucene段(segments),每个段是一个小型独立索引
-
段文件包括:
.fdt:字段数据文件,存储文档原始内容.fdx:字段索引,指向.fdt文件中的内容.tim:词条字典,存储词条和指向.doc文件的指针.tip:词条索引,帮助快速查找词条字典.doc:倒排索引文件,记录词条到文档的映射.pos:位置信息,用于短语查询.nvd/.nvm:规范化因子,用于文档评分.dvd/.dvm:文档值,用于聚合和排序
查询执行流程:
-
IndexSearcher为每个段创建SegmentReader -
使用
TermDictionary查找词条,获取倒排列表(posting lists) -
应用过滤器使用
BitSet快速过滤文档 -
使用配置的相关性算法(如BM25、TF-IDF)计算评分
-
使用多种缓存提高性能:
- 文档缓存(Document Cache)
- 字段数据缓存(Field Data Cache)
- 过滤器缓存(Filter Cache)
- 查询缓存(Query Cache)
-
使用
PriorityQueue保存每个段的顶部匹配文档 -
合并所有段的结果到一个有序结果集
文件访问优化:
- 使用
MMapDirectory或NIOFSDirectory提高文件访问效率 - 应用Lucene的复合文件格式(CFS)减少文件句柄数量
- 使用
IndexSearcher重用以减少I/O操作
8. 结果合并与排序
每个分片独立处理查询:
- 在分片的倒排索引上执行查询
- 执行过滤、评分和聚合操作
- 将本地结果返回给协调节点
协调节点收集并合并来自各个分片的结果。
9. 格式化响应
协调节点根据请求的格式构建最终响应。
10. 返回结果
协调节点将搜索结果返回给客户端。
这个过程确保了Elasticsearch能够在分布式环境中高效地执行查询,并提供一致的结果。