德令哈市公司网站建设,广州建设工程网站,西宁网站建设嘉荐君博l,南充市房地产备案查询一、ES的三种分页的选择
es实现分页查询#xff0c;在ES中有三种方式可以实现分页#xff1a;fromsize、scroll、search_after
1、fromsize 分页
原理#xff1a;
假设取的页数较大时(深分页)#xff0c;如请求第20页#xff0c;Elasticsearch不得不取出所有分片上的第…一、ES的三种分页的选择
es实现分页查询在ES中有三种方式可以实现分页fromsize、scroll、search_after
1、fromsize 分页
原理
假设取的页数较大时(深分页)如请求第20页Elasticsearch不得不取出所有分片上的第1页到第20页的所有文档并做排序
最终再取出from后的size条结果作为最终的返回值。假设你有16个分片则需要在coordinate node汇总到 shards* (fromsize)条记录即需要16*(2010)记录后做一次全局排序。
所以当索引非常非常大(千万或亿)是无法使用from size 做深分页的分页越深则越容易OOM即便不OOM也很消耗CPU和内存资源。因此ES使用index.max_result_window:10000作为保护措施 即默认 from size 不能超过10000虽然这个参数可以动态修改
也可以在配置文件配置但是最好不要这么做应该改用ES游标来取得数据。在使用过程中有一些典型的使用场景比如分页、遍历等。在使用关系型数据库中我们被告知要注意甚至被明确禁止使用深度分页同理在 Elasticsearch 中也应该尽量避免使用深度分页。es为了性能限制了我们分页的深度es目前支持的最大的 max_result_window 10000fromsize二者之和不能超过1w也就是说我们不能分页到1w条数据以上。 fromsize分页原理很简单比如需要查询10条数据,es则需要执行fromsize条数据然后根据偏移量截断前N条处理后返回。随着偏移量的增大这个时间会呈几何式增长。
如何解决fromsize 分页带来的性能问题
1.在业务逻辑上禁止深度分页比如不允许查询10000条以后的数据2.更换分页方式采用游标 scroll的方式
2、游标 scroll 分页 Scroll往往是应用于后台批处理任务中不能用于实时搜索因为这个scroll相当于维护了一份当前索引段的快照信息这个快照信息是你执行这个scroll查询时的快照。在这个查询后的任何新索引进来的数据都不会在这个快照中查询到。但是它相对于from和size不是查询所有数据然后剔除不要的部分而是记录一个读取的位置保证下一次快速继续读取。查询时会自动返回一个_scroll_id通过这个id可以继续查询 public function list(Request $request){if (!isset($request-scroll_id)) {$params [scroll 30s, //快照存活的时间 1m -一分钟size $request-limit,index $this-index,type $this-type,];$response app(es)-search($params);} else {$response app(es)-scroll([scroll_id $request-scroll_id, //...using our previously obtained _scroll_idscroll 30s, // and the same timeout window]);}return [scroll_id $response[_scroll_id],data $response[hits][hits],];}游标 scroll 带来的问题
这种分页方式虽然查询变快了但滚动上下文代价很高每一个 scroll_id 不仅会占用大量的资源特别是排序的请求而且是生成的历史快照对于数据的变更不会反映到快照上,那么在实时情况下如果处理深度分页的问题呢es 给出了 search_after 的方式这是在 5.0 版本才提供的功能。
3、search_after分页
searchAfter的方式通过维护一个实时游标来避免scroll的缺点它可以用于实时请求和高并发场景。 search_after的理念是在不同分片上假设有5个分片先按照指定顺序排好根据我们传的search_after值 然后仅取这个值之后的size个文档。这 5*size 个文档拿到Es内存中排序后返回前size个文档即可。避免了浅分页导致的内存爆炸情况经实际使用性能良好,ES空闲状态下查询耗时稳定在50ms以内平均10~20ms。 public function list(Request $request){if (!isset($request-search_after)) {$params [size $request-limit,index $this-index,type $this-type,body [sort [[_id desc,],],],];} else {$params [size $request-limit,index $this-index,type $this-type,body [sort [[_id desc,],],search_after [$request-search_after],],];}$response app(es)-search($params);return [//项目中需优化数组溢出此处仅为简单演示search_after $response[hits][hits][count($response[hits][hits]) - 1][sort][0], data $response[hits][hits],];注意 当我们使用search_after时from值必须设置为0或者-1当然你也可以不设置这个from参数。当存在search_after参数时不允许出现scroll参数
search_after 带来的问题
ElasticSearch之Search_After的注意事项
1.搜索时需要指定sort,并且保证值是唯一的可以通过加入_id或者文档body中的业务唯一值来保证 2.再次查询时使用上一次最后一个文档的sort值作为search_after的值来进行查询 3.不能使用随机跳页只能是下一页或者小范围的跳页一次查询出小范围内各个页数利用缓存等技术来实现小范围分页比较麻烦比如从第一页调到第五页则依次查询出2,3,4页的数据利用每一次最后一个文档的sort值进行下一轮查询客户端或服务端都可以进行如果跳的比较多则可能该方法并不适用 它与滚动API非常相似但与它不同search_after参数是无状态的它始终针对最新版本的搜索器进行解析。因此排序顺序可能会在步行期间发生变化具体取决于索引的更新和删除
4、总结
from size 分页如果数据量不大或者from、size不大的情况下效率还是蛮高的。但是在深度分页的情况下这种使用方式效率是非常低的并发一旦过大还有可能直接拖垮整个ElasticSearch的集群。 scroll 分页通常不会用在客户端因为每一个 scroll_id 都会占用大量的资源一般是后台用于全量读取数据使用 search_after通过维护一个实时游标来避免scroll的缺点它可以用于实时请求和高并发场景一般用于客户端的分页查询 大体而言就是在这三种分页方式中from size不适合数据量很大的场景scroll不适合实时场景而search after在es5.x版本之后应运而生较好的解决了这个问题。