from + size 浅分页
“浅”分页可以理解为简单意义上的分页。它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询。
GET test_dev/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": 28
}
}
]
}
},
"size": 10,
"from": 20,
"sort": [
{
"timestamp": {
"order": "desc"
},
"_id": {
"order": "desc"
}
}
]
}
-
其中,from定义了目标数据的偏移值,size定义当前返回的数目。默认from为0,size为10,即所有的查询默认仅仅返回前10条数据。
-
在这里有必要了解一下from/size的原理:因为es是基于分片的,假设有5个分片,from=100,size=10。则会根据排序规则从5个分片中各取回100条数据,然后汇总成500条数据后选择最前面的10条数据。
-
做过测试,越往后的分页,执行的效率越低。总体上会随着from的增加,消耗时间也会增加。而且数据量越大,就越明显
scroll 深分页
from+size查询在10000-50000条数据(1000到5000页)以内的时候还是可以的,但是如果数据过多的话,就会出现性能问题。
为了解决此问题,elasticsearch提出了一个scroll滚动的方式。
scroll 类似于sql中的cursor,使用scroll,每次只能获取一页的内容,然后会返回一个scroll_id。根据返回的这个scroll_id可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景。
GET test_dev/_search?scroll=5m
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": 28
}
}
]
}
},
"size": 10,
"from": 0,
"sort": [
{
"timestamp": {
"order": "desc"
},
"_id": {
"order": "desc"
}
}
]
}
- scroll=5m表示设置scroll_id保留5分钟可用。
- 使用scroll必须要将from设置为0。
- size决定后面每次调用_search搜索返回的数量
- 通过数据返回的_scroll_id读取下一页内容,每次请求将会读取下10条数据,直到数据读取完毕或者scroll_id保留时间截止
GET _search/scroll
{
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAJZ9Fnk1d......",
"scroll": "5m"
}
注意:请求的接口不再使用索引名了,而是 _search/scroll,其中GET和POST方法都可以使用。
- scroll删除
根据官方文档的说法,scroll的搜索上下文会在scroll的保留时间截止后自动清除,但是我们知道scroll是非常消耗资源的,所以一个建议就是当不需要了scroll数据的时候,尽可能快的把scroll_id显式删除掉。
清除指定的scroll_id:
DELETE _search/scroll/DnF1ZXJ5VGhlbkZldGNo.....
清除所有的scroll:
DELETE _search/scroll/_all
search_after 深分页
scroll 的方式,官方的建议不用于实时的请求(一般用于数据导出),因为每一个 scroll_id 不仅会占用大量的资源,而且会生成历史快照,对于数据的变更不会反映到快照上。
search_after 分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。
为了找到每一页最后一条数据,每个文档必须有一个全局唯一值,官方推荐使用 _uid 作为全局唯一值,其实使用业务层的 id 也可以。
GET test_dev/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": 28
}
}
]
}
},
"size": 20,
"from": 0,
"sort": [
{
"timestamp": {
"order": "desc"
},
"_id": {
"order": "desc"
}
}
]
}
- 使用search_after必须要设置from=0。
- 这里我使用timestamp和_id作为唯一值排序。
- 我们在返回的最后一条数据里拿到sort属性的值传入到search_after。
使用sort返回的值搜索下一页:
GET test_dev/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": 28
}
}
]
}
},
"size": 10,
"from": 0,
"search_after": [
1541495312521,
"d0xH6GYBBtbwbQSP0j1A"
],
"sort": [
{
"timestamp": {
"order": "desc"
},
"_id": {
"order": "desc"
}
}
]
}
修改默认分页限制值10000
可以使用下面的方式来改变ES默认深度分页的index.max_result_window 最大窗口值
curl -XPUT http://127.0.0.1:9200/my_index/_settings -d '{ "index" : { "max_result_window" : 500000}}'
其中my_index为要修改的index名,500000为要调整的新的窗口数。将该窗口调整后,便可以解决无法获取到10000条后数据的问题。
注意事项
通过上述的方式解决了我们的问题,但也引入了另一个需要我们注意的问题,窗口值调大了后,虽然请求到分页的数据条数更多了,但它是用牺牲更多的服务器的内存、CPU资源来换取的。要考虑业务场景中过大的分页请求,是否会造成集群服务的OutOfMemory问题。
获取总数据量
修改最大限制值之后确实可以使from+size查询到更后面页的数据(10000之后),但是每次查询得到的总数量最大任然是10000,要想获取大于1万的查询数据量,可以分两步查询,第一步使用scroll查询获取总数据量;第二步使用from+size查询每页的数据,并设置分页。这样即解决了from+size无法查询10000之后的数据,也解决了scroll无法跳页的问题。
使用scroll可能遇到的问题:
Caused by: org.elasticsearch.ElasticsearchException: Trying to create too many scroll contexts.
Must be less than or equal to: [500].
This limit can be set by changing the [search.max_open_scroll_context] setting.
- 这个报错是从es的日志文件中查出来的,大致意思是:尝试创建更多的scroll对象失败了,scroll对象总数量应该控制在500以内。可修改search.max_open_scroll_context的值来改变500这个阈值。
- 原因:通过scroll 深分页可知道,es服务端会在内存中生成一个scroll_id对象,并会为该值指定过期时间,翻页的时候使用scroll_id来获取下一页的数据。默认情况下,一个实例下面仅可以创建最多500个scroll上下文对象,也就是500个scroll_id。报此错误的原因就是创建scroll上下文对象失败,因为当前已经存在500个这样的对象了。
- 解决办法:
- 通过观察可以发现,即使不做任何的处理,过一会就又可以发起scroll请求了,这是因为时间超过了scroll生命周期时间,scroll对象自己死掉了一些。
- 按照提示说的,修改search.max_open_scroll_context的值
put http://{{es-host}}/_cluster/settings
{
"persistent": {
"search.max_open_scroll_context": 5000
},
"transient": {
"search.max_open_scroll_context": 5000
}
}
- 在使用完scroll_id之后立即调用删除接口,删除该scroll对象
引用
- 互联网…
技术交流QQ群:1158377441
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/14913.html