Elasticsearch Search Scroll API(滚动查询)

这篇具有很好参考价值的文章主要介绍了Elasticsearch Search Scroll API(滚动查询)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

参考:Elasticsearch Search Scroll API(滚动查询) - 简书

Elasticsearch 中,传统的分页查询使用from+size的模式,from就是页码,从 0 开始。默认情况下,当(from+1)*size大于 10000 时,也就是已查询的总数据量大于 10000 时,会出现异常。

如下,用循环模拟一个连续分页查询:

public void search() {
        // 记录页码
        int page = 0;
        // 记录已经查询到总数据量
        long total = 0;

        while (true) {
            NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                    // 设置分页
                    .withPageable(PageRequest.of(page, 1000))
                    .withSort(new FieldSortBuilder("commentCount").order(SortOrder.DESC))
                    .build();

            SearchHits<Book> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Book.class);
            if (!searchHits.hasSearchHits()) {
                break;
            }
            for (SearchHit<Book> searchHit : searchHits.getSearchHits()) {
                Book book = searchHit.getContent();
            }
            page++;
            System.out.println(page);
            System.out.println(total += searchHits.getSearchHits().size());
        }
}

最终当 page 等于 10 时会抛出如下异常:

Elasticsearch Search Scroll API(滚动查询)

Caused by: ElasticsearchException[Elasticsearch exception [type=illegal_argument_exception, reason=Result window is too large, from + size must be less than or equal to: [10000] but was [11000]. 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.]]

从异常信息中,我们可以发现官方给我们提供了两种方案来解决这个问题:

1、max_result_window

  • 将 Elasticsearch 配置参数index.max_result_window修改为大于 100000 的值,对应的 RESTful API 如下:
PUT book/_settings
{
    "index": {
        "max_result_window": 1000000
    }
}

虽然可以通过修改index.max_result_window来解决查询时数据量的限制,但是这并不是不推荐的做法,当数据量达到百万、千万级别时,使用from+size模式查询时性能会越来越差,每次查询的耗时也会越来越久,严重影响体验,同时对 CPU 和内存的消耗也很大的。

2、scroll api

如果需要查询大量的数据,可以考虑使用 Search Scroll API,这是一种更加高效的方式。

如果直接使用 Java Client,可以参考官方的 API 文档:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.9/java-rest-high-search-scroll.html

我们这里还是和 SpringBoot 整合去使用,其实核心的用法都是很类似的。如下同样模拟一个连分页查询:

public void scrollSearch() {
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withSort(new FieldSortBuilder("commentCount").order(SortOrder.DESC))
                .build();
        // 设置每页数据量
        nativeSearchQuery.setMaxResults(1000);
    
        long scrollTimeInMillis = 60 * 1000;
        // 第一次查询
        SearchScrollHits<Book> searchScrollHits = elasticsearchRestTemplate.searchScrollStart(scrollTimeInMillis, nativeSearchQuery, Book.class, IndexCoordinates.of("book"));
        String scrollId = searchScrollHits.getScrollId();

        while (searchScrollHits.hasSearchHits()) {
            System.out.println(total += searchScrollHits.getSearchHits().size());

            for (SearchHit<Book> searchHit : searchScrollHits.getSearchHits()) {
                Book book = searchHit.getContent();
            }
            // 后续查询
            searchScrollHits = elasticsearchRestTemplate.searchScrollContinue(scrollId, scrollTimeInMillis, Book.class, IndexCoordinates.of("book"));
            scrollId = searchScrollHits.getScrollId();
        }

        List<String> scrollIds = new ArrayList<>();
        scrollIds.add(scrollId);
        // 清除 scroll
        elasticsearchRestTemplate.searchScrollClear(scrollIds);
}

以下几点需要注意:

  • setMaxResults(1000)用来设置查询时每页的数据量,我这里使用 Elasticsearch7.9 有这个方法,如果其它旧版本没有这个方法,可以使用PageRequest.of(0, 1000)来设置,注意页码要为 0。
  • 第一次查询使用searchScrollStart(),后续查询使用searchScrollContinue(),查询结果中都携带了一个scrollId
  • 除了第一次查询外,后续的查询都需要携带scrollId,可以理解为游标,用它来控制分页。和from+size模式中页码是一个作用。
  • scrollTimeInMillis,表示查询结果中scrollId的有效时间,单位毫秒,可根据实际情况设置。
  • 查询结束后,需要使用searchScrollClear()清除 scroll。
  • from+size分页查询模式中,我们可以指定任意合理的页码,实现跳页查询;但使用scroll api就无法实现跳页查询了,因为除了第一次查询外的其它查询都要依赖上一次查询返回的scrollId,这一点需要注意。


原文中可能会空查一次,少许修改代码,如下:文章来源地址https://www.toymoban.com/news/detail-418916.html

void searchScroll(){
        NativeSearchQuery query = new NativeSearchQuery(QueryBuilders.matchAllQuery());
        query.setMaxResults(1);//设置每页数据量
        query.addSort(Sort.by(Sort.Direction.DESC,"age"));

        long scrollTimeInMillis=5_000;
        long currentTotal=0;
        int pageNo=1;
        List<String> scrollIdList = new ArrayList<>();

        //scroll一共有三个方法:searchScrollStart(第一次查询)、searchScrollContinue(第二次到最后一次)、searchScrollClear(查询完成后执行)

        //第一次查询使用:searchScrollStart
        SearchScrollHits<People> searchScrollHits = this.elasticsearchRestTemplate.searchScrollStart(scrollTimeInMillis, query, People.class, IndexCoordinates.of("people_index"));
        String scrollId = searchScrollHits.getScrollId();
        scrollIdList.add(scrollId);
        System.out.println("scrollId:"+scrollId);

        long totalHits = searchScrollHits.getTotalHits();
        currentTotal=searchScrollHits.getSearchHits().size();
        System.out.println("totalHits:"+totalHits);

        List<People> list = searchScrollHits.get().map(SearchHit::getContent).collect(Collectors.toList());
        System.out.println("============pageNo:==========="+pageNo);
        for (People people : list) {
            System.out.println(people);
        }

        while (currentTotal<totalHits){
            SearchScrollHits<People> searchScrollHitsContinue = elasticsearchRestTemplate.searchScrollContinue(scrollId, scrollTimeInMillis, People.class, IndexCoordinates.of("people_index"));
            scrollId=searchScrollHitsContinue.getScrollId();
            scrollIdList.add(scrollId);
            pageNo++;
            if(searchScrollHitsContinue.hasSearchHits()){
                currentTotal+=searchScrollHitsContinue.getSearchHits().size();
                List<People> peopleList = searchScrollHitsContinue.get().map(SearchHit::getContent).collect(Collectors.toList());
                System.out.println("============pageNo:==========="+pageNo);
                for (People people : peopleList) {
                    System.out.println(people);
                }
            }else{
                System.out.println("============pageNo not hasSearchHits===========");
                break;
            }
        }
        System.out.println(scrollIdList);
        elasticsearchRestTemplate.searchScrollClear(scrollIdList);
    }

到了这里,关于Elasticsearch Search Scroll API(滚动查询)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch Search API之(Request Body Search 查询主体)(1)

    “failed”:0 }, “hits”:{ “total”:1, “max_score”:0.2876821, “hits”:[ { “_index”:“map_highlighting_01”, “_type”:“_doc”, “_id”:“erYsbmcBeEynCj5VqVTI”, “_score”:0.2876821, “_source”:{ “context”:“城中西路可以受理外地二代身份证的办理。” }, “highlight”:{ // @1 “context”:[ “城中西

    2024年04月13日
    浏览(48)
  • ElasticSearch6.x版本的Scroll滚动查询讲解及Kibana和SpringBoot实操演示

    ElasticSearch中在进行普通的查询时, 默认只会查询出来10条数据 。我们通过设置ElasticSearch中的 size 可以将最终的查询结果从 10 增加到 10000 。但这时候如果我们需要查询的数据大于10000条怎么办呢?这时候有两种方法: 深度分页 和 滚动查询 。在这里我们优选选择 滚动查询

    2024年01月17日
    浏览(36)
  • Elasticsearch From/Size、Scroll、Search After对比

    Elasticsearch From/Size、Scroll、Search After对比 可以使用from和size参数对结果进行分页。from参数定义要获取的第一个结果的偏移量。 size 参数允许您配置要返回的最大匹配数。 简单来说,需要查询from + size 的条数时,coordinate node就向该index的其余的shards 发送同样的请求,等汇总到(

    2023年04月08日
    浏览(38)
  • ElasticSearch系列 - SpringBoot整合ES:实现分页搜索 from+size、search after、scroll

    01. 数据准备 ElasticSearch 向 my_index 索引中索引了 12 条文档: 02. ElasticSearch 如何查询所有文档? ElasticSearch 查询所有文档 根据查询结果可以看出,集群中总共有12个文档,hits.total.value=12, 但是在 hits 数组中只有 10 个文档。如何才能看到其他的文档? 03. ElasticSearch 如何指定搜

    2023年04月08日
    浏览(44)
  • Elasticsearch:Async search API

    当我们想要执行持续时间较长的查询时,执行异步操作是一个很好的选择。 在这篇文章中,我们将学习如何管理异步查询。异步操作由 async search API 执行。 异步搜索 API 具有与 _search API 相同的参数,因此你无需构建特殊查询。 在我之前的文章 “Elasticsearch:异步搜索 - as

    2023年04月08日
    浏览(45)
  • Elastic Search的RestFul API入门:如何进行ES的查询-search

    在这篇教学文章中,我们将深入探讨Elasticsearch的search功能。这是一个非常强大且灵活的功能,它允许我们对存储在Elasticsearch中的数据进行各种复杂的查询和分析。本章的目标是让读者理解如何进行Elasticsearch的搜索,以及如何在搜索过程中自主调整搜索参数,从而灵活地控制

    2024年02月03日
    浏览(47)
  • java使用ElasticSearch的scroll查询,高效的解决es查询数量的限制。

    (1)首先我们要明白es的查询机制:ES的搜索是分2个阶段进行的,即 Query阶段和Fetch阶段 。 Query阶段 比较轻量级,通过查询倒排索引,获取满足查询结果的文档ID列表。 Fetch阶段 比较重,需要将每个分片的查询结果取回,在协调结点进行 全局 排序。 通过From+size这种方式分批

    2024年02月03日
    浏览(82)
  • Elasticsearch ES 简单查询 Query String Search 入门

    尝试了text类型排序需要特别处理下. \\\"reason\\\" : \\\"Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [name] in order to load field data by uninverting the inverted index.

    2024年02月16日
    浏览(45)
  • elasticsearch 深度分页查询 Search_after(图文教程)

    前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱 search_after 是 Elasticsearch 提供的一种分页查询方式,它可以用来在已经排序的结果集中进行分页查询。 search_after查询步骤如下(下面有具体的例子帮助理解):

    2024年04月11日
    浏览(47)
  • ElasticSearch7.3学习(二十二)----Text字段排序、Scroll分批查询场景解析

    场景:数据库中按照某个字段排序,sql只需写order by 字段名即可,如果es对一个 text field 进行排序,es中无法排序。因为文档入倒排索引表时,分词存入,es无法知道此字段的真实值。这样的结果往往不准确,因为分词后是多个单词,再排序就不是我们想要的结果了。 通常有两

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包