【ES 分页限制】分页最多不能超1W记录排序以及解决方案以及scroll和scroll-scan区别

1【理解】

1 请求第20页,假设你有16个分片,则需要在coordinate node 汇总到 shards* (from+size)条记录,即需要 16*(20+10)记录后做一次全局排序,再最终取出 from后的size条结果作为最终的响应。

2 当索引非常非常大(千万或亿),是无法安装 from + size 做深分页的,分页越深则越容易OOM,即便不OOM,也是很消耗CPU和内存资源的。

CPU、内存和IO消耗容易理解,网络带宽问题稍难理解一点。在 query 阶段,每个shards需要返回 1,000,100 条数据给 coordinating node,而 coordinating node 需要接收 10 * 1,000,100 条数据,即使每条数据只有 _doc _id 和 _score,这数据量也很大了,而且,这才一个查询请求,那如果再乘以100呢?

3 为了不合理使用 from + size 造成OOM及最终的集群不稳定,官方在后2.x版本中已增加限定 index.max_result_window:10000作为保护措施 ,即默认 from + size 不能超过1万。当然这个参数可以动态修改,也可以在配置文件配置——但最好不要这么做,除非你知道这意味着什么

4  根据业务字段属性作为游标
数据随时间在变化,数据丢失重复等不可预期的结果 ;不能保证 游标的准确性;

 

curl -XPUT "http://11.12.84.126:9200/_audit_0102/_settings" -d '{

"index": {

"max_result_window": 100000

}

}'

 

OOM

???

 

"reason": {

"type": "query_phase_execution_exception",

"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10010]. 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."

 

2【解决方案】于是出现了:

海量导数据第一版:

1 A scrolled search takes a snapshot in time(适时)

2 Normally, the background merge process optimizes the index by merging together smaller segments to create new bigger segments, at which time the smaller segments are deleted(合并小的分段到新的大的分段,同时小的分段被删除)于是更多的file handles 被占用

 

3【应用】

POST /note_/recommend_note/_search?scroll=1m

{

"size": 2,

"query": {

"match" : {

"operation_tags" : "育儿"

}

}

}

返回:

"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAF1RhFl9ISGlIYnNhUzlhVDdLd01wOGc4WXcAAAAAABl0kRZyTmhoMmJNVlJzQ1VzOEROVUhHRlZnAAAAAAAZdJIWck5oaDJiTVZSc0NVczhETlVIR0ZWZwAAAAAAGXSTFnJOaGgyYk1WUnNDVXM4RE5VSEdGVmcAAAAAABdUYhZfSEhpSGJzYVM5YVQ3S3dNcDhnOFl3"



第二步:

POST /_search/scroll

{

"scroll" : "1m",

"scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAF1RhFl9ISGlIYnNhUzlhVDdLd01wOGc4WXcAAAAAABl0kRZyTmhoMmJNVlJzQ1VzOEROVUhHRlZnAAAAAAAZdJIWck5oaDJiTVZSc0NVczhETlVIR0ZWZwAAAAAAGXSTFnJOaGgyYk1WUnNDVXM4RE5VSEdGVmcAAAAAABdUYhZfSEhpSGJzYVM5YVQ3S3dNcDhnOFl3"

} 一直执行相同的请求直到返回结果为空



第三步:GET /_nodes/stats/indices/search



"indices": {

"search": {

"open_contexts": 3,

"query_total": 1668363,

"query_time_in_millis": 14717409,

"query_current": 0,

"fetch_total": 1570213,

"fetch_time_in_millis": 1323603,

"fetch_current": 0,

"scroll_total": 62483,

"scroll_time_in_millis": 679341,

"scroll_current": 3,

"suggest_total": 0,

"suggest_time_in_millis": 0,

"suggest_current": 0

}

}



第四步清理 单个:

DELETE /_search/scroll/DnF1ZXJ5VGhlbkZldGNoBQAAAAAAFpvrFm5mZ1ZidkgwUW9hOUR4VVkwUnQ2SmcAAAAAABl1KhZyTmhoMmJNVlJzQ1VzOEROVUhHRlZnAAAAAAAWm-oWbmZnVmJ2SDBRb2E5RHhVWTBSdDZKZwAAAAAAF1VFFl9ISGlIYnNhUzlhVDdLd01wOGc4WXcAAAAAABdVRhZfSEhpSGJzYVM5YVQ3S3dNcDhnOFl3

{

"succeeded": true,

"num_freed": 5

}

所有:

DELETE /_search/scroll/_all

{

"succeeded": true,

"num_freed": 3

}



第二种做法

POST ip:port/my_index/my_type/_search?search_type=scan&scroll=1m&size=50

{

"query": { "match_all": {}}

}





java:

第一次查询

SearchResponse response1 = client.prepareSearch("_audit_0221").setTypes("_log_0221")

.setQuery(boolQueryBuilder)

.setSearchType(.setSearchType(SearchType.DEFAULT))

.setSize(10).setScroll(TimeValue.timeValueMinutes(5))

.addSort("logTime", SortOrder.DESC)

.execute().actionGet();//第一次查询

for (SearchHit searchHit : response1.getHits().hits()) {

biz handle....;

}

第二次查询



while (response1.getHits().hits().length>0) {

for (SearchHit searchHit : response1.getHits().hits()) {

System.out.println(searchHit.getSource().toString());

}

response1 = client.prepareSearchScroll(response1.getScrollId()).setScroll(TimeValue.timeValueMinutes(5))

.execute().actionGet();

}

一次性查询清理现场:

ClearScrollRequest request = new ClearScrollRequest();

request.addScrollId(scrollId);

client.clearScroll(request);

4【评价】

这时如果你的产品经理要求你按照常规的做法去分页,你可以很明确的告诉他,你的系统不支持这么深度的分页,翻的越深,性能也就越差。

 

不过这种深度分页场景在现实中确实存在,有些场景下,我们可以说服产品经理很少有人会翻看很久之前的历史数据,但是有些场景下可能一天都产生几百万。这个时候我们可以根据具体场景具体分析。

参考https://my.oschina.net/u/1787735/blog/3024051

5 【scroll和scroll-scan】区别

1. scroll支持排序,scroll-scan不支持排序,是按照索引顺序返回,可以提高查询效率。

2. scroll-scan第一次查询只支持返回id,没有结果。

总结:

1. es的分页查询不支持深度分页,如果偏要使用要结合具体业务场景进行使用。不能当成关系型数据库中的分页进行使用。

2. 要想提高产品体验和查询效率不能过于依赖技术,要结合需求进行分析以提高体验,因为很多搜索类产品都不支持深度分页。

3. 如果在不涉及排序的情况下尽量使用scroll-scan,它是按照索引顺序返回,提高效率。

PS:elasticSearch各个版本可能都稍有区别,但是原理相同。

你可能感兴趣的:(es)