ElasticSearch操作之游标查询Scroll Search

sifeimeng 2020-05-14

一.  什么是游标查询(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评论 2020-05-25