本文从一个示例入手,从代码层面分析 elastic search 查询文档的完整过程。

新建索引 cn-msg,设置 3 分片,1 副本

PUT localhost:9200/cn-msg
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}

写入文档

POST localhost:9200/cn-msg/_doc
{
    "messageId": "6a5955ee28ec4ce483ebb8a4d6a4d214",
    "status": 1
}

查询文档

POST localhost:9200/cn-msg/_search
{
  "query": {
    "match": {
      "messageId": "6a5955ee28ec4ce483ebb8a4d6a4d214"
    }
  }
}

接收到查询文档请求的节点称为协调节点,协调节点收到请求,将查询请求转发给 3 个分片所在的节点,等待这 3 个分片的响应,汇总响应发送给客户端(暂且可以这么认为,这里还有一步 query then fetch)。

转发查询请求:

// org.elasticsearch.action.search.AbstractSearchAsyncAction#run

for 循环遍历 3 个分片,向 3 个分片发送查询请求:

协调节点收到分片的响应后,保存响应并检查是否所有的响应都已收到:

 couter 对象的注释如下:

/**
 * This is a simple base class to simplify fan out to shards and collect their results. Each results passed to
 * {@link #onResult(SearchPhaseResult)} will be set to the provided result array
 * where the given index is used to set the result on the array.
 */
final class CountedCollector<R extends SearchPhaseResult> {
    private final ArraySearchPhaseResults<R> resultConsumer;
    private final CountDown counter;
    private final Runnable onFinish;
    private final SearchPhaseContext context;

可以看出这是一个存储分片响应的抽象过的容器,当所有的分片响应都收到后,即 CountDown 值为 0,则可以对文档 id 进行汇总(排序,聚合):

// org.elasticsearch.action.search.QueryPhaseResultConsumer#reduce

 

但是,协调节点收到的分片响应仅包含 doc id,如果要获取文档数据还得再发送一次 fetch 请求:

// org.elasticsearch.action.search.FetchSearchPhase#innerRun

 当协调节点接收到所有存在数据的分片节点的 fetch 响应后,就可以发送响应给客户端了

 

posted on 2023-09-15 10:36  偶尔发呆  阅读(40)  评论(0编辑  收藏  举报