Elasticsearch 的一次查询过程

97 阅读3分钟

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保存每个段的顶部匹配文档

  • 合并所有段的结果到一个有序结果集

文件访问优化

  • 使用MMapDirectoryNIOFSDirectory提高文件访问效率
  • 应用Lucene的复合文件格式(CFS)减少文件句柄数量
  • 使用IndexSearcher重用以减少I/O操作

8. 结果合并与排序

每个分片独立处理查询:

  • 在分片的倒排索引上执行查询
  • 执行过滤、评分和聚合操作
  • 将本地结果返回给协调节点

协调节点收集并合并来自各个分片的结果。

9. 格式化响应

协调节点根据请求的格式构建最终响应。

10. 返回结果

协调节点将搜索结果返回给客户端。

这个过程确保了Elasticsearch能够在分布式环境中高效地执行查询,并提供一致的结果。