[ElasticSearch]ES操作之游标查询Scroll Search
一、什么是ES游标查询(Scroll) 顾名思义,相当于用“一把游标”标记“查询的位置”。二、为什么要使用游标查询 在默认情况下,ES查询每次返回的数量最多只有1W条,且只能是前1W条。这意味着,在不修改配置的情况下,想通过分页的方式(如下)拿到1W条之后的数据是做不到的。GET /索引/类型/_search{"size": 10000,"from": 5000,"query": {...},
一、什么是ES游标查询(Scroll)
顾名思义,相当于用“一把游标”标记“查询的位置”。
二、为什么要使用游标查询
在默认情况下,ES查询每次返回的数量最多只有1W条,且只能是前1W条。这意味着,在不修改配置的情况下,想通过分页的方式(如下)拿到1W条之后的数据是做不到的。
GET /索引/类型/_search
{
"size": 10000,
"from": 5000,
"query": {
...
},
"aggs": {
...
}
}
以上查询在默认情况下会报异常,提示超过数据窗口大小。对于这种情况,解决方案就是:游标查询。
三、如何使用游标查询
DSL的用法:
GET 索引/类型/_search?scroll=1m
{
"size": 10000,
"query": {
"match_all": {}
}
}
其中,1m表示过期时间为1分钟。
查询结果的第一行会有:
"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBAAAAAAABO-dFmRFSU9NM1VNU2JxNG9UUlNnSmpXMVEAAAAAAL7J_hYxT0dJOVJVMVFxU2I0N2xCR2IyVzJnAAAAAAC- SmQWWk1aN0sxUmRSQmFNS3EwVFh0R0luUQAAAAAAvkplFlpNWjdLMVJkUkJhTUtxMFRYdEdJblE=",
这个_scroll_id就相当于书签,之后的查询带着这个书签,就能根据size不断拿到之后的数据,前提是在过期时间之内。之后的查询DSL:
GET _search/scroll
{
"scroll":"1m",
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoBAAAAAAABPP1FmRFSU9NM1VNU2JxNG9UUlNnSmpXMVEAAAAAAL7OTxYxT0dJOVJVMVFxU2I0N2xCR2IyVzJnAAAAAAC-j70WVVlOZkxQRzJRLXlMRlVMbEQtalBfUQAAAAAAyWm-Fk9HdGx1b3VsUXRLZHV4c1E1OExja0E="
}
将获取的scroll_id作为条件继续查询即可,不需要再指定索引和类型。因为scroll_id具有唯一性,在过期时间内,之后查询的scroll_id是不变的。
四、基于java代码
RestClient lowClient = RestClient.builder(new HttpHost("主机",端口))
.setMaxRetryTimeoutMillis(300000).build();
RestHighLevelClient client = new RestHighLevelClient(lowClient);
SearchRequest request = new SearchRequest("索引").types("类型");
//这里一次查1W条
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().size(10000);
request.source(builder).searchType(SearchType.DEFAULT);
//这句代码就是设置游标查询和过期时间
request.scroll(TimeValue.timeValueMinutes(5));
SearchResponse response = client.search(request);
// search
SearchResponse response = client.search(request);
//定义游标
String scrollId = null;
if (response != null && response.getHits().getHits().length > 0) {
for (SearchHit hit : response.getHits().getHits()) {
//TODO
}
//拿到游标
scrollId = response.getScrollId();
}
//一直查询,直到没有游标返回(查询到底了)
while (true){
if(scrollId == null){
break;
}
SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId).scroll(TimeValue.timeValueMinutes(5));;
response = client.searchScroll(searchScrollRequest);
if (response != null && response.getHits().getHits().length > 0) {
for (SearchHit hit : response.getHits().getHits()) {
//TODO
}
scrollId = response.getScrollId();
}else {
break;
}
}
到这里,游标查询的基本操作就OK了。有一点需要注意:游标的方式相当于mysql中生成快照的方式,如果在游标查询期间有增删改操作,查询结果是获取不到最新数据的。
更多推荐
所有评论(0)