Elasticsearch搜索流程解析

本文详细介绍了Elasticsearch的搜索流程,包括协调节点的Query和Fetch阶段,以及数据节点如何响应Query和Fetch请求。搜索分为两阶段,首先在协调节点进行query,然后在数据节点fetch数据。Query阶段向所有相关分片发送请求,Fetch阶段根据query结果获取具体文档内容。数据节点的查询执行基于Lucene,使用缓存提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

ES的读取分为GET和Search两种操作,这两种读取操作有较大的差异,GET/MGET必须指定三元组:_index、_type、_id。也就是说,根据文档id从正排索引中获取内容。而Search不指定_id,根据关键词从倒排索引中获取内容。

可接收客户端请求的节点称为协调节点。在协调节点,搜索任务被执行成一个两阶段过程,即query then fetch。真正执行搜索任务的节点称为数据节点。当搜索任务执行在分布式系统上时,整体流程如下图所示。

ES分布式搜索流程

需要两个阶段才能完成搜索的原因是,在查询的时候不知道文档位于哪个分片,因此索引的所有分片(某个副本)都要参与搜索,然后协调节点将结果合并,再根据文档ID获取文档内容。例如,有5个分片,查询返回前10个匹配度最高的文档,那么每个分片都查询出当前分片的TOP 10,协调节点将5*10=50的结果再次排序,返回最终TOP 10的结果给客户端。

下面我们按照请求涉及的两个节点来分析流程:协调节点和数据节点。

协调节点流程

两阶段相应的实现位置:查询(Query)阶段——InitialSearchPhase;取回(Fetch)阶段——FetchSearchPhase。它们都继承自SearchPhase。

Query阶段

  1. 协调节点广播查询请求到所有相关分片时,可以是主分片或副分片,协调节点将在之后的请求中轮询所有的分片副本来分摊负载。请求是基于shard遍历的,如果列表中的N个shard位于同一个节点,则向其发送N次请求,并不会把请求合并为一个。

     // InitialSearchPhase.java
     public final void run() {
         if (shardsIts.size() > 0) {
             // 分shard发送搜索请求
             for (int index = 0; index < shardsIts.size(); index++) {
                 final SearchShardIterator shardRoutings = shardsIts.get(index);
                 performPhaseOnShard(index, shardRoutings, shardRoutings.nextOrNull());
             }
         }
     }
    
  2. 构建异步线程将搜索请求发送到真正的shard,监听所有shard query请求,成功返回回调onShardResult方法,失败返回回调onShardFailure方法。

     // InitialSearchPhase.java
     private void performPhaseOnShard(final int shardIndex, final SearchShardIterator shardIt, final ShardRouting shard) {
     	// 构建异步线程将搜索请求发送到真正的shard
         Runnable r = () -> {
             final Thread thread = Thread.currentThread();
             try {
                 executePhaseOnShard(shardIt, shard,
                     new SearchActionListener<FirstResult>(shardIt.newSearchShardTarget(shard.currentNodeId()), shardIndex) {
                         @Override
                         public void innerOnResponse(FirstResult result) {
                             try {
                                 onShardResult(result, shardIt);
                             } finally {
                                 executeNext(pendingExecutions, thread);
                             }
                         }
    
                         @Override
                         public void onFailure(Exception t) {
                             try {
                                 onShardFailure(shardIndex, shard, shard.currentNodeId(), shardIt, t);
                             } finally {
                                 executeNext(pendingExecutions, thread);
                             }
                         }
                     });
             }
         };
    
         if (throttleConcurrentRequests) {
             pendingEx
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值