ES的滚动搜索
游标查询 Scroll
滚动搜索API,即Search Scroll API,可通过搜索请求,获取大量搜索结果。滚动搜索有点类似于数据库中的分页查询。
ES对于from+size的个数是有限制的,二者之和不能超过1w。当所请求的数据总量大于1w时,可用scroll来代替from+size。
如果一次性要查出来比如10万条数据,那么性能会很差,此时一般会采取用scoll滚动查询,一批一批的查,直到所有数据都查询完处理完。
scroll
查询 可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。
游标查询允许我们 先做查询初始化,然后再批量地拉取结果。 这有点儿像传统数据库中的 cursor 。
游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。 它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 视图 一样。
深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段
_doc
来排序。 这个指令让 Elasticsearch 仅仅从还有结果的分片返回下一批结果。
启用游标查询可以通过在查询的时候设置参数 scroll
的值为我们期望的游标查询的过期时间。 游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。 这个过期时间的参数很重要,因为保持这个游标查询窗口需要消耗资源,所以我们期望如果不再需要维护这种资源就该早点儿释放掉。 设置这个超时能够让 Elasticsearch 在稍后空闲的时候自动释放这部分资源。
GET /old_index/_search?scroll=1m { "query": { "match_all": {}}, "sort" : ["_doc"], "size": 1000 }
保持游标查询窗口一分钟。 |
|
关键字 |
这个查询的返回结果包括一个字段 _scroll_id`, 它是一个base64编码的长字符串 ((("scroll_id"))) 。 现在我们能传递字段 `_scroll_id
到 _search/scroll
查询接口获取下一批结果:
GET /_search/scroll { "scroll": "1m", "scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs=" }
注意再次设置游标查询过期时间为一分钟。 |
这个游标查询返回的下一批结果。 尽管我们指定字段 size
的值为1000,我们有可能取到超过这个值数量的文档。 当查询的时候, 字段 size
作用于单个分片,所以每个批次实际返回的文档数量最大为 size * number_of_primary_shards
。
注意游标查询每次返回一个新字段 _scroll_id`。每次我们做下一次游标查询, 我们必须把前一次查询返回的字段 `_scroll_id
传递进去。 当没有更多的结果返回的时候,我们就处理完所有匹配的文档了。
使用ES高级客户端实现:
/**
* 滚动搜索
*
* @return
*/
public String scroll() {
// 步骤一 初始化滚动搜索的上下文信息。 ------------------------------
// 构建滚动搜索请求
SearchRequest searchRequest = new SearchRequest("secisland");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("detail", "IPS面板"));
// 设置单分片查询的数量
searchSourceBuilder.size(10);
searchRequest.source(searchSourceBuilder);
// 设置滚动间隔
searchRequest.scroll(TimeValue.timeValueMillis(1L));
try {
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 步骤二 检索所有相关文档。 ---------------------------
// 滚动搜索id
String scrollId = searchResponse.getScrollId();
// 文档
SearchHits hits = searchResponse.getHits();
while (hits != null && hits.getHits().length != 0) {
// 设置滚动标识符
SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
scrollRequest.scroll(TimeValue.timeValueSeconds(30));
SearchResponse searchResponse1 = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
// 读取新的scrollId
scrollId = searchResponse1.getScrollId();
// 读取新的hits
hits = searchResponse1.getHits();
}
System.out.println("结果" + searchResponse);
} catch (IOException e) {
System.out.println("执行失败" + e.getMessage());
}
return null;
}
以上代码分为两个步骤实现滚动搜索。
步骤1:初始化滚动搜索的上下文信息。
在执行滚动搜索API时,滚动搜索会话的初始化必须带有滚动搜索参数的搜索请求,即SearchRequest。在执行该搜索请求时,Elasticsearch会检测到滚动搜索参数的存在,并在相应的时间间隔内保持搜索上下文活动。
步骤2:检索所有相关文档。
首先在SearchScrollRequest中设置上文提及的滚动标识符和新的滚动间隔;其次在设置好SearchScrollRequest后,将其传送给searchScroll方法。在请求发出后,Elasticsearch服务器会返回另一批带有新的滚动标识符的结果。依次类推,用户需要在新的SearchScrollRequest中设置前文提及的滚动标识符和新的滚动间隔,以便获取下一批次的结果。这个过程会在一个循环中重复执行,直到不再有任何结果返回。这意味着滚动搜索已经完成,所有匹配的文档都已被检索。
SearchScrollRequest的可选参数
在SearchScrollRequest中,除滚动标识符外,还提供了可选参数供用户进行配置。SearchScrollRequest提供的主要可选参数是滚动搜索的过期时间,代码如下所示:
在实际开发中,如果读者没有为SearchScrollRequest设置滚动标识符,则一旦初始滚动时间过期(即初始搜索请求中设置的滚动时间过期),则滚动搜索的上下文也会过期。
清除滚动搜索的上下文
在滚动搜索请求执行后,用户可以使用Clear Scroll API删除最后一个滚动标识符,以释放滚动搜索的上下文。当滚动搜索超时时间到期时,这个过程也会自动发生。一般在滚动搜索会话后,需立即清除滚动搜索的上下文。在执行清除滚动搜索上下文的请求之前,需要构建清除滚动搜索请求,即ClearScrollRequest。ClearScrollRequest需要把滚动标识符作为参数输入,构建ClearScrollRequest的代码如下所示:
在构建ClearScrollRequest时,不仅可以配置单个滚动标识符,还可以配置多个滚动标识符。我们继续在上述方法中添加如下代码:
执行清除滚动搜索请求在ClearScrollRequest构建后,即可执行清除滚动搜索请求了。与文档索引请求类似,清除滚动搜索请求也有同步和异步两种执行方式。这里就不细说看,跟之前的一样。
本文地址:https://blog.csdn.net/weixin_40663800/article/details/110947725