ES查询内核流程
1 概述
ES查询分为GET和SEARCH两类,GET查询指定_index,_type,_id,从正排索引中获取指定Doc。SEARCH查询不指定_id,根据关键字从倒排索引中获取内容。以下主要分析SEARCH过程:
(1) SEARCH过程分为两个阶段:Query和Fetch。
(2) SEARCH过程涉及两类节点:协调节点和数据节点。
Query阶段客户端将请求发送给协调节点,协调节点将请求转发到数据节点上索引的每个主分片或副本分片中,每个分片在本地执行查询,并进行打分,添加结果到大小为from+size的本地有序优先队列中。每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,协调节点合并这些值到自己的优先队列中,产生一个全局排序后的列表。
Fetch阶段根据Query阶段的结果,协调节点向相关数据节点发送GET请求,分片所在节点向协调节点返回数据,协调节点等待所有文档被取得,然后返回给客户端。
2 源码分析
2.1 协调节点流程
2.1.1 Query阶段:
1.解析请求
RestSearchAction#prepareRequest方法中将请求体解析为SearchRequest数据结构:
2.构造目的shard列表
将请求涉及的本集群shard列表和远程集群的shard列表合并,TransportSearchAction#executeSearch完成了合并操作,调用了mergeShardIterators:
3.遍历所有shard发送请求
请求是基于shard遍历的,如果列表中有N个shard位于同一个节点,则向其发送N次请求。AbstractSearchAsyncAction#run完成此操作, performPhaseOnShard发送请求:
4.收集返回结果
AbstractSearchAsyncAction#onShardResult完成收集操作,consumeResult对收集的结果进行合并:
successfulShardException检查是否所有请求都已收到回复,是否进入下一阶段:
以上方法调用的OnPhaseDone方法会调用executeNextPhase,从而开始执行Fetch取回阶段。
2.1.2 Fetch阶段:
1. 发送Fetch请求
Query阶段的executeNextPhrase方法触发Fetch阶段,Fetch阶段的起点为FetchSearchPharse#innerRun函数,再进一步调用executeFetch方法,从查询阶段的shard列表中遍历来获取数据。
executeFetch的主要实现:
executeFetch中定义一个Listener,每成功获取一个shard数据后就执行counter.onResult,其中调用对结果的处理回调,把result保存到数组中,然后执行countDown:
2. 收集结果
收集器定义在innerRun中,包括收到的shard数据存放在哪里,收集完成后谁来处理:
fetchResults用于存储从某个shard收集到的结果,每收到一个shard的数据就执行一次counter.countDown。当所有shard数据收集完毕后,countDown会触发执行finishPhase:
moveToNextPhase方法执行下一阶段,下一阶段要执行的任务定义在FetchSearchPhase构造函数中,主要是触发ExpandSearchPharse,取回阶段完成之后执行ExpandSearchPharse#run,主要判断是否启用字段叠加,根据需要实现字段叠加功能。
3. 回复客户端
ExpandSearchPharse执行完之后回复客户端,在sendResonsePharse方法中实现:
2.3 数据节点流程
2.2.1 响应Query请求
主要过程就是执行查询,然后发送Response。Query,Fetch请求的处理入口注册于SearchTransportService#registerRequestHandler:
查询入口在searchService.executeQueryPhase中。查询时,先看是否允许cache,由以下配置决定:
index.requests.cache.enable
默认为true,会把查询结果放到cache中,查询时优先从cache中取。这个cache由节点的所有分片共享,基于LRU算法实现:空间满的时候删除最近最少使用的数据。所以cache并不缓存全局检索结果。
核心的查询封装在queryPhase.execute(context)中,其中调用Lucene实现检索,同时实现聚合:
其中包含几个核心功能:
executeInternal():调用Lucene的searcher.search()实现搜索;
rescoreRhase:全文检索且需要打分;
suggestPhase:自动补全及纠错;
aggregationPhase:实现聚合。
2.2.2 响应Fetch请求
主要过程是执行Fetch,然后发送Response:
对Fetch响应的实现封装在searchService.executeFetrchPhase中,核心是调用fetchPhase.execute(context)。按照命中的doc取得相关数据,填充到SearchHits中,最终封装到FetchSearchResult中
- 点赞
- 收藏
- 关注作者
评论(0)