ElasticSearch之处理深度分页

  • 一、常规分页
  • 二、scroll分页
  • 三、search_after

在ES中实现分页的方法有三种,我们逐个分析一下他们的优缺点。

一、常规分页

在ES中,我们可以给查询条件加fromsize达到分页的效果,比如:

get test_index/_doc/_search
{"query":{"match_all":{}},"from":1000,"size":3
}

但是这种使用方式效率是非常低的,比如上面那条语句,意味着ES要在每个分片上面匹配排序并得到1003条数据,协调节点拿到这些数据再进行排序处理,最终返回我们需要的3条数据。

其次,ES为了性能考虑,限制了分页的深度,目前ES支持最大的max_result_window = 10000,也就是说当我们指定分页个数超过10000时,ES就不支持了

比如

get test_index/_doc/_search
{"query":{"match_all":{}},"from":9998,"size":3
}
------------------------------

"Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."

总结
缺点:常规分页性能低下,不支持深度分页,默认10000条数据后不支持查询,深度分页会给每个分片的内存造成一定程度的压力。

优点:实现起来比较简单

场景:适合数据量小、没有深度分页的场景下可以使用。

二、scroll分页

如果我们分页一次请求需要获取较大的数据集,scroll是一个非常好的解决方案。

如果想要使用,只需要在请求中加一个参数scroll=? ?是什么呢?

其实,es的滚动搜索,是先搜索一批数据,然后下次再搜索一批数据,以此类推,直到搜索出全部数据。scroll搜索会在第一次请求的时候,保存一个当时的试图快照,之后都只会基于该旧的试图快照来提供数据搜索,如果这个快照时间内数据进行了变更,用户是看不到的。而我们添加的参数scroll=?就是指定快照时间。

注意:ES默认限制存活的scrollId个数为500个,超出报错。

比如:

get test_index/_doc/_search?scroll=1m
{"query":{"match_all":{}},"from":0,"size":1
}
------------------------------
{"_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmZrX09mWXpvUjZPV2hJVlF3b0hGY0EAAAAAAAAQsxZyT3ZKTDlLZlJIeUdkSEdONmtnb0pB","took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 9,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "test_index","_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : {"name" : {"uid" : 1,"name" : "程大帅","address" : "上海市汤臣一品"}}}]}
}

会发现和平常的搜索查询不同,本次响应中携带了参数"_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmZrX09mWXpvUjZPV2hJVlF3b0hGY0EAAAAAAAAQsxZyT3ZKTDlLZlJIeUdkSEdONmtnb0pB"

接下来我们可以使用这个scroll_id来进行滚动查询,因为我们上面指定了滚动的步长:1,所以我们再使用scroll命令的时候不用指定步长,会每次都给我们一条数据,直到快照内数据为空。

post _search/scroll
{"scroll":"5m","scroll_id":"FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmZrX09mWXpvUjZPV2hJVlF3b0hGY0EAAAAAAAAQsxZyT3ZKTDlLZlJIeUdkSEdONmtnb0pB"
}

快照内数据滚动完毕就会是下面的样子。

{"_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmZrX09mWXpvUjZPV2hJVlF3b0hGY0EAAAAAAAAQsxZyT3ZKTDlLZlJIeUdkSEdONmtnb0pB","took" : 1,"timed_out" : false,"terminated_early" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 9,"relation" : "eq"},"max_score" : 1.0,"hits" : [ ]}
}

总结
优点:解决了深度分页问题,性能相对来说还可以。

缺点:快照时间内数据修改,无法及时感应到。滚动查询时需要维护scroll_id。ES默认限制存活的scrollId个数为500个,不适用开放于客户端使用。

场景:大数据量情况下,比如海量数据的导出。或者后台统计聚合任务等等。

三、search_after

上面我们介绍了常规分页和scroll滚动分页。

常规分页无法避免深度分页问题。
scroll能够解决深度分页问题但是无法实现较实时的查询。

这时候可以考虑使用第三种分页方式search_after,这其实是一个假分页,根据上一页最后一条数据来确定下一页的开始位置。但是使用它每个文档必须要有一个全局唯一的值,比如我们的业务id,或者官方自动生成的id:_uid等,只要能表示其唯一性即可。

示例1:
比如我们使用官方生成的uid来进行search_after查询。

get test_index/_doc/_search
{"query":{"match_all":{}},"from":0,"size":1,"sort":{"_id":{"order":"desc"}}
}
----------------------
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 7,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "test_index","_type" : "_doc","_id" : "xc7BBn4B1rLCL6KXklDg","_score" : null,"_source" : {"name" : {"id" : 6,"name" : "程六帅","address" : "上海市汤臣六品"}},"sort" : ["xc7BBn4B1rLCL6KXklDg"]}]}
}

下次分页需要将上述分页结果集的最后一条数据的排序值带上。

get test_index/_doc/_search
{"query":{"match_all":{}},"from":0,"size":1,"search_after":["xc7BBn4B1rLCL6KXklDg"],"sort":{"_id":{"order":"desc"}}
}
-----------------------------------------
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 7,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "test_index","_type" : "_doc","_id" : "xM7BBn4B1rLCL6KXdVCl","_score" : null,"_source" : {"name" : {"id" : 5,"name" : "程五帅","address" : "上海市汤臣五品"}},"sort" : ["xM7BBn4B1rLCL6KXdVCl"]}]}
}

示例2:
实际上ES为我们提供的uid是无序的,所以我们最好文档中要包含一个唯一键,比如我们现在对文档中的唯一键id来进行search_after。

get test_index/_doc/_search
{"query":{"match_all":{}},"from":0,"size":1,"sort":{"name.id":"desc"}
}
-----------------------
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 7,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "test_index","_type" : "_doc","_id" : "xc7BBn4B1rLCL6KXklDg","_score" : null,"_source" : {"name" : {"id" : 6,"name" : "程六帅","address" : "上海市汤臣六品"}},"sort" : [6]}]}
}

再根据返回值的sort来进行search_after的参数构建。

get test_index/_doc/_search
{"query":{"match_all":{}},"search_after":["6"],"from":0,"size":1,"sort":{"name.id":"desc"}
}
---------------------------
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 7,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "test_index","_type" : "_doc","_id" : "xM7BBn4B1rLCL6KXdVCl","_score" : null,"_source" : {"name" : {"id" : 5,"name" : "程五帅","address" : "上海市汤臣五品"}},"sort" : [5]}]}
}

总结
优点:性能强劲,根据唯一排序键来滚动查询,不存在深度分页问题,也能够避免scroll的数据非实时性。

缺点:

  1. 实现较为复杂,需要文档中存在全局唯一键。
  2. 每一次查询都要带上上一次查询的结果。
  3. 无法实现跳页请求。

场景:适用于海量数据分页场景。

ElasticSearch之处理深度分页相关推荐

  1. 如何在elasticsearch里面使用深度分页功能

    2019独角兽企业重金招聘Python工程师标准>>> 前面的文章提到过es默认的from+size的分页方式返回的结果数据集不能超过1万点,超过之后返回的数据越多性能就越低. 这是 ...

  2. Elasticsearch:Scroll深度分页及返回大量数据

    目录 方法一 设置size 方法二 from and size分页 方法三 scroll and scan滚屏. 在使用ES时,有时候不可避免的要返回大量的数据或者说返回满足你的查询条件的全部数据,而 ...

  3. 3.Elasticsearch学习之深度分页、游标查询、以及批量操作

    1.深度分页 1.分页查询 POST /shop/_doc/_search { "query": { "match_all": {} },"from& ...

  4. 京东面试题:ElasticSearch深度分页解决方案

    前言 Elasticsearch 是一个实时的分布式搜索与分析引擎,在使用过程中,有一些典型的使用场景,比如分页.遍历等. 在使用关系型数据库中,我们被告知要注意甚至被明确禁止使用深度分页,同理,在 ...

  5. elasticsearch java 分页查询_elasticsearch深度分页问题

    正版包邮elasticsearch实战与原理 70.1元 包邮 (需用券) 去购买 > elasticsearch分页对于用过es的人应该都会使用 ,和数据库的分页类似,如下所示,通过from ...

  6. ElasticSearch利用Search After解决深度分页问题

    ElasticSearch利用Search After解决深度分页问题 1.ElasticSearch常见分页 2.ElasticSearch深度分页问题 3.ElasticSearch深度分页问题的 ...

  7. ElasticSearch 分页查询及深度分页原理与实现

    查询流程 查询阶段 在初始化查询阶段(query phase),查询被向索引中的每个分片副本(原本或副本)广播.每个分片在本地执行搜索并且建 立了匹配 document 的优先队列(priority ...

  8. Elasticsearch的深度分页

    Elasticsearch的深度分页 查看篇博客可以先查看下elasticsearch的DSL搜索方便理解:传送门接描述 一.深度分页分析 1.深度分页:(from:9999:size:10) 第99 ...

  9. ElasticSearch 深度分页详解

    来源 | OSCHINA 社区 作者 | 京东云开发者-何守优 原文链接:https://my.oschina.net/u/4090830/blog/5593128 1 前言 ElasticSearc ...

最新文章

  1. 三层架构中ajax,基于mvc三层架构和ajax技术实现最简单的文件上传
  2. gdb+gdbserver
  3. CNCF 宣布 Helm 成为基金会下一个重点孵化项目
  4. 深度学习(十六)基于2-channel network的图片相似度判别-CVPR 2015
  5. boost::safe_numerics模块实现测试添加 constexpr
  6. sony z2 android 5.0,索尼Xperia Z2 5.0 root教程_索尼Z2获取5.0系统的root
  7. python遍历循环中的遍历结构可以是什么_(一)Python入门-4控制语句:06for循环结构-遍历各种可迭代对象-range对象...
  8. 计算机术语中英文对照表(流水线/微架构/体系结构/指令集)
  9. win10下正确使用Sublime Text搭建python调试环境
  10. JDK历史所有版本下载地址(附Oracle帐号)
  11. Ubuntu22.04运行网易云音乐错误
  12. 【干货】常用的14个获取数据的网站。
  13. 羊皮卷之七 我要笑遍世界
  14. 基于QQ空间热修复原理实践
  15. 2019美国大学计算机专业,2019美国计算机专业什么大学好
  16. 深入理解CAS算法原理
  17. BS和CS架构,软件开发的瀑布模型,快速原型模型、螺旋模型、敏捷开发、软件测试分类,测试的分类和理解
  18. java平面内有n个矩形_java有关于M*N矩形求解正方形长方形个数问题
  19. 批量导出导入数据及附件文件ZIP包
  20. 锂电池SOC估计Simulink模型/卡尔曼滤波估算SOC

热门文章

  1. 依据经度纬度计算距离方式
  2. phoenix的映射
  3. 【京东】职级、薪酬、绩效全认知
  4. 博弈论学习笔记(七)纳什均衡伯川德模型与选民投票
  5. SS524V100 RTL8152B(USB转网卡)驱动移植
  6. oracle 创建sde,创建多个sde库
  7. iPhone 4s手机内部构造
  8. render()函数进行服务器端渲染(详细)
  9. python循环3次停止_Python 基础 — 循环
  10. [Java]-zip包的使用