【Elasticsearch源码】查询源码分析(一)

本文主要分析Elasticsearch的查询源码,探讨DFS_QUERY_THEN_FETCH和QUERY_THEN_FETCH两种查询方式,以及查询请求从Rest层到Transport层的处理流程。详细介绍了查询请求的入口、分发过程,以及在协调节点如何处理查询任务。

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

1 前言

前面分析过ES的写入流程源码,详情见【Elasticsearch源码】写入源码分析

Elasticsearch(ES)的查询接口具有分布式的数据检索、聚合分析能力,数据检索能力用于支持全文检索、日志分析等场景,如Github平台上的代码搜索、基于ES的各类日志分析服务等;聚合分析能力用于支持指标分析、APM等场景,如监控场景、应用的日活/留存分析等。

本文基于6.7.1版本,主要分析ES的分布式执行框架及查询主体流程,探究ES如何实现分布式查询、数据检索、聚合分析等能力。

2 查询基本流程

图片来自官网,源代码取自6.7.1版本:

在这里插入图片描述

  1. 客户端可以将查询发送到任意节点,接收到查询的节点会作为该查询的协调节点;
  2. 协调节点解析查询语句,向对应数据分片分发查询子任务;
  3. 各个分片将本地的查询结果返回给协调节点,进过协调节点汇聚后返回给客户端。

如图所示:客户端将请求发送到Node3节点,Node3节点进行查询解析之后,将请求分发到0号和1号分片所在的Node2和Node1,两者再讲各地分片的查询数据返回至Node3,最终Node3进行汇聚,然后返回客户端。

从实际的实现来看,协调节点的处理逻辑远比上述流程复杂,不同类型的查询对应的协调节点的处理逻辑有一定的差别。

下面先来介绍下常见的2类查询,在之前的版本有3类查询:DFS_QUERY_THEN_FETCH、QUERY_AND_FETCH和QUERY_THEN_FETCH,5.3版本之后,QUERY_AND_FETCH已经被移除。

2.1 DFS_QUERY_THEN_FETCH

搜索里面有一种算分逻辑是根据TF(Term Frequency)和DF(Document Frequency)计算基础分,但是Elasticsearch中查询的时候,是在每个Shard中独立查询的,每个Shard中的TF和DF也是独立的,虽然在写入的时候通过_routing保证Doc分布均匀,但是没法保证TF和DF均匀,那么就有会导致局部的TF和DF不准的情况出现,这个时候基于TF、DF的算分就不准。

为了解决这个问题,Elasticsearch中引入了DFS查询,比如DFS_query_then_fetch,会先收集所有Shard中的TF和DF值,然后将这些值带入请求中,再次执行query_then_fetch,这样算分的时候TF和DF就是准确的。

2.2 QUERY_THEN_FETCH

ES默认的查询方式,在查询的过程中,分为query和fetch两个阶段:

Query Phase: 进行分片粒度的数据检索和聚合,注意此轮调度仅返回文档id集合,并不返回实际数据。

协调节点:解析查询后,向目标数据分片发送查询命令。
数据节点:在每个分片内,按照过滤、排序等条件进行分片粒度的文档id检索和数据聚合,返回结果。

Fetch Phase: 生成最终的检索、聚合结果。

协调节点:归并Query Phase的结果,得到最终的文档id集合和聚合结果,并向目标数据分片发送数据抓取命令。
数据节点:按需抓取实际需要的数据内容。

3 查询源码流程分析

这里以默认的QUERY_THEN_FETCH查询为例:

3.1 查询请求入口

这一块逻辑和所有的ES请求的处理是类似的,可以参考bulk请求的过程。以Rest请求为例:

在这里插入图片描述
Rest分发由RestController模块完成。在ES节点启动时,会加载所有内置请求的Rest Action,并把对应请求的Http路径和Rest Action作为<Path, RestXXXAction>二元组注册到RestController中。这样对于任意的Rest请求,RestController模块只需根据Http路径,即可轻松找到对应的Rest Action进行请求分发。RestSearchAction的注册样例如下:

    public RestSearchAction(Settings settings, RestController controller) {
   
        super(settings);
        controller.registerHandler(GET, "/_search", this);
        controller.registerHandler(POST, "/_search", this);
        controller.registerHandler(GET, "/{index}/_search", this);
        controller.registerHandler(POST, "/{index}/_search", this);
        controller.registerHandler(GET, "/{index}/{type}/_search", this);
        controller.registerHandler(POST, "/{index}/{type}/_search", this);
    }

Rest层用于解析Http请求参数,RestRequest解析并转化为SearchRequest,然后再对SearchRequest做处理,这块的逻辑在prepareRequest方法中,部分代码如下:

    public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
   
    	//根据RestRequest构建SearchRequest
        SearchRequest searchRequest = new SearchRequest();
        IntConsumer setSize = size -> searchRequest.source
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值