第
ElasticSearch?深度分页示例解析
目录1前言2from+size分页方式2.1Query阶段2.2Fetch阶段2.3ES示例2.4实现示例2.5小结3Scroll分页方式3.1执行过程
1前言
ElasticSearch是一个实时的分布式搜索与分析引擎,常用于大量非结构化数据的存储和快速检索场景,具有很强的扩展性。纵使其有诸多优点,在搜索领域远超关系型数据库,但依然存在与关系型数据库同样的深度分页问题,本文就此问题做一个实践性分析探讨
2from+size分页方式
from+size分页方式是ES最基本的分页方式,类似于关系型数据库中的limit方式。from参数表示:分页起始位置;size参数表示:每页获取数据条数。例如:
GET/wms_order_sku/_search
query:{
match_all:{}
from:10,
size:20
该条DSL语句表示从搜索结果中第10条数据位置开始,取之后的20条数据作为结果返回。这种分页方式在ES集群内部是如何执行的呢?在ES中,搜索一般包括2个阶段,Query阶段和Fetch阶段,Query阶段主要确定要获取哪些doc,也就是返回所要获取doc的id集合,Fetch阶段主要通过id获取具体的doc。
2.1Query阶段
如上图所示,Query阶段大致分为3步:
第一步:Client发送查询请求到Server端,Node1接收到请求然后创建一个大小为from+size的优先级队列用来存放结果,此时Node1被称为coordinatingnode(协调节点);第二步:Node1将请求广播到涉及的shard上,每个shard内部执行搜索请求,然后将执行结果存到自己内部的大小同样为from+size的优先级队列里;第三步:每个shard将暂存的自身优先级队列里的结果返给Node1,Node1拿到所有shard返回的结果后,对结果进行一次合并,产生一个全局的优先级队列,存在Node1的优先级队列中。(如上图中,Node1会拿到(from+size)*6条数据,这些数据只包含doc的唯一标识_id和用于排序的_score,然后Node1会对这些数据合并排序,选择前from+size条数据存到优先级队列);
2.2Fetch阶段
如上图所示,当Query阶段结束后立马进入Fetch阶段,Fetch阶段也分为3步:
第一步:Node1根据刚才合并后保存在优先级队列中的from+size条数据的id集合,发送请求到对应的shard上查询doc数据详情;第二步:各shard接收到查询请求后,查询到对应的数据详情并返回为Node1;(Node1中的优先级队列中保存了from+size条数据的_id,但是在Fetch阶段并不需要取回所有数据,只需要取回从from到from+size之间的size条数据详情即可,这size条数据可能在同一个shard也可能在不同的shard,因此Node1使用multi-get来提高性能)第三步:Node1获取到对应的分页数据后,返回给Client;
2.3ES示例
依据上述我们对from+size分页方式两阶段的分析会发现,假如起始位置from或者页条数size特别大时,对于数据查询和coordinatingnode结果合并都是巨大的性能损耗。例如:索引wms_order_sku有1亿数据,分10个shard存储,当一个请求的from=1000000,size=10。在Query阶段,每个shard就需要返回1000010条数据的_id和_score信息,而coordinatingnode就需要接收10*1000010条数据,拿到这些数据后需要进行全局排序取到前1000010条数据的_id集合保存到coordinatingnode的优先级队列中,后续在Fetch阶段再去获取那10条数据的详情返回给客户端。分析:这个例子的执行过程中,在Query阶段会在每个shard上均有巨大的查询量,返回给coordinatingnode时需要执行大量数据的排序操作,并且保存到优先级队列的数据量也很大,占用大量节点机器内存资