ES源码阅读——seach流程
search流程,分为查询query阶段,和fetch取回阶段,也叫query then fetch。
为什么要分成2个阶段。因为协调节点,也不知道数据分别在哪个分片上,所有在协调节点会找到所有分片,让每个分片执行查询,最后在协调节点将结果合并,返回给客户端。
假设有5个分片,查询相关度最高的10个文档,那么协调节点会让5个分片都执行查询,每个分片都要查询相关度最高的10个文档,协调节点再将50个文档再次排序,最终返回top10给客户端。
协调节点:接收客户端请求的节点。
数据节点:真正执行搜索任务的节点是数据节点。
search流程
1、合并分片
执行查询的逻辑是在TransportSearchAction类下面,为何要起这个名字,传过来查询的动作。用SearchAction岂不是更好。
之所以用Transport,是因为查询的逻辑属于Transport模块
ES的几个模块:
- Cluster
- allocation
- discovery
- gateway
- indices
- http
- transport
- engine
查询的逻辑,会将本地的分片列表和远程的分片列表合并到一起
// 本地集群分片列表
GroupShardsIterator<ShardIterator> localShardsIterator = clusterService.operationRouting().searchShards(clusterState,
concreteIndices, routingMap, searchRequest.preference(), searchService.getResponseCollectorService(), nodeSearchCounts);
// 将本地集群分片列表和远程集群分片列表合并,得到目的分片列表
GroupShardsIterator<SearchShardIterator> shardIterators = mergeShardsIterators(localShardsIterator, localIndices,
remoteShardIterators);
2、执行查询
找到所有分片信息后,开启线程进行查询,使用的方法是searchAsyncAction。
AbstractSearchAsyncAction类是个抽象类,父类是InitialSearchPhase,InitialSearchPhase类继承了SearchPhase。SearchPhase这个类实现了CheckedRunnable接口。
@FunctionalInterface
public interface CheckedRunnable<E extends Exception> {
void run() throws E;
}
InitialSearchPhase的run方法,对所有分片执行遍历
if (shardsIts.size() > 0) {
int maxConcurrentShardRequests = Math.min(this.maxConcurrentShardRequests, shardsIts.size());
for (int index = 0; index < maxConcurrentShardRequests; index++) {
final SearchShardIterator shardRoutings = shardsIts.get(index);
assert shardRoutings.skip() == false;
// 分片执行遍历的逻辑
performPhaseOnShard(index, shardRoutings, shardRoutings.nextOrNull());
}
}
fetch流程
关于作者
后端程序员,五年开发经验,从事互联网金融方向。技术公众号「清泉白石」。如果您在阅读文章时有什么疑问或者发现文章的错误,欢迎在公众号里给我留言。