AIQ | elasticsearch 的查询流程详解



转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com

AIQ 机器学习大数据 知乎专栏 点击关注

我们都知道 es 是一个分布式的存储和检索系统,在存储的时候默认是根据每条记录的 _id 字段做路由分发的,这意味着 es 服务端是准确知道每个 document 分布在那个 shard 上的。

相对比于 CURD 上操作,search 一个比较复杂的执行模式,因为我们不知道那些 document 会被匹配到,任何一个 shard 上都有可能,所以一个 search 请求必须查询一个索引或多个索引里面的所有 shard 才能完整的查询到我们想要的结果。

找到所有匹配的结果是查询的第一步,来自多个 shard 上的数据集在分页返回到客户端的之前会被合并到一个排序后的 list 列表,由于需要经过一步取 top N 的操作,所以 search 需要进过两个阶段才能完成,分别是 query 和 fetch。

(一)query(查询阶段)

当一个 search 请求发出的时候,这个 query 会被广播到索引里面的每一个 shard(主 shard 或副本 shard),每个 shard 会在本地执行查询请求后会生成一个命中文档的优先级队列。

这个队列是一个排序好的 top N 数据的列表,它的 size 等于 from+size 的和,也就是说如果你的 from 是 10,size 是 10,那么这个队列的 size 就是 20,所以这也是为什么深度分页不能用 from+size 这种方式,因为 from 越大,性能就越低。

es 里面分布式 search 的查询流程如下:
1,客户端发送一个 search 请求到 Node 3 上,然后 Node 3 会创建一个优先级队列它的大小 =from+size

2,接着 Node 3 转发这个 search 请求到索引里面每一个主 shard 或者副本 shard 上,每个 shard 会在本地查询然后添加结果到本地的排序好的优先级队列里面。

3,每个 shard 返回 docId 和所有参与排序字段的值例如 _score 到优先级队列里面,然后再返回给 coordinating 节点也就是 Node 3,然后 Node 3 负责将所有 shard 里面的数据给合并到一个全局的排序的列表。
上面提到一个术语叫 coordinating node,这个节点是当 search 请求随机负载的发送到一个节点上,然后这个节点就会成为一个 coordinating node,它的职责是广播 search 请求到所有相关的 shard 上,然后合并他们的响应结果到一个全局的排序列表中然后进行第二个 fetch 阶段,注意这个结果集仅仅包含 docId 和所有排序的字段值,search 请求可以被主 shard 或者副本 shard 处理,这也是为什么我们说增加副本的个数就能增加搜索吞吐量的原因,coordinating 节点将会通过 round-robin 的方式自动负载均衡。

(二)fetch(读取阶段)

query 阶段标识了那些文档满足了该次的 search 请求,但是我们仍然需要检索回 document 整条数据,这个阶段称为 fetch

流程如下:

1,coordinating 节点标识了那些 document 需要被拉取出来,并发送一个批量的 mutil get 请求到相关的 shard 上

2,每个 shard 加载相关 document,如果需要他们将会被返回到 coordinating 节点上

3,一旦所有的 document 被拉取回来,coordinating 节点将会返回结果集到客户端上。
这里需要注意,coordinating 节点拉取的时候只拉取需要被拉取的数据,比如 from=90,size=10,那么 fetch 只会读取需要被读取的 10 条数据,这 10 条数据可能在一个 shard 上,也可能在多个 shard 上所以
coordinating 节点会构建一个 multi-get 请求并发送到每一个 shard 上,每个 shard 会根据需要从 _source 字段里面获取数据,一旦所有的数据返回,coordinating 节点会组装数据进入单个 response 里面然后将其返回给最终的 client。

总结:

本文介绍了 es 的分布式 search 的查询流程分为 query 和 fetch 两个阶段,在 query 阶段会从所有的 shard 上读取相关 document 的 docId 及相关的排序字段值,并最终在 coordinating 节点上收集所有的结果数进入一个全局的排序列表后,然后获取根据 from+size 指定 page 页的数据,获取这些 docId 后再构建一个 multi-get 请求发送相关的 shard 上从 _source 里面获取需要加载的数据,最终再返回给 client 端,至此整个 search 请求流程执行完毕,至于为什么 es 要通过两个阶段来完成一次 search 请求而不是一次搞定,大家可以在评论区留言讨论。


更多高质资源 尽在AIQ 机器学习大数据 知乎专栏 点击关注

转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com