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
}

保持游标查询窗口一分钟。

关键字 _doc 是最有效的排序顺序。

这个查询的返回结果包括一个字段 _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

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐