关于SpringBoot集成ES Scroll API(滚动查询)的实践

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

背景:

那是年初在某个交付项目,从用户侧获知了一个elastic search作为分布式数据库的一个瓶颈,那就是单次查询量超过了ES的默认单次查询上限10000。

在大部分业务下,为了执行ES的数据查询,开发者往往都直接使用了query某个条件获取数据,这些条件对应的数据大多都不会超过10000,因此在一般测试下难以发现这类问题。但系统经过经年累月的使用,数据量在不断增长,又因业务需求不可清除旧数据的情况下,这类问题就诞生了。
scroll api,JavaWeb编程,java

于是,我想到Elasticsearch 中,传统的分页查询使用from+size的模式,类似如下语句:

GET /<index>/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "match_all": {}
  }
}

那我们可以大可尝试使用while的方式,每次在拼接query时改变from的值为from+size,那么我每次拿到的就是下一个分页,如此往复,那也可以实现无穷尽也。

大胆尝试实践:

public void search() {
        int from = 0;
        long total = 0;
        int size = 100;

        while (true) {
            NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                    .withPageable(PageRequest.of(from, size))
                    .withSort(new FieldSortBuilder("id").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());
        }
}

实现完成,点击运行。

Yes!我失败了。

于是,我意识到我并没有认真看关于报错的信息,在我自我批评和自我反省下,再次对报错信息认真解读
scroll api,JavaWeb编程,java
强大的Elasticsearch已经告诉了我答案,建议我扩大index.max_result_window的上限参数,或者参阅scroll api的文档。

学习

至此,开启了我对Elasticsearch Search Scroll API(滚动查询)的学习和探索!

在浅显的入门Scroll API之后,相比之下,自己之前的想法就像是关公面前耍了一次大刀——小聪明了,总结我自己的想法,那就是当程序运行到极限时,我的代码就好似拼装了以下的一个查询语句,尝试在可视化插件中执行该语句,发现依然会报错,报错与单次查询10000条并无差别。

GET /<index>/_search
{
  "from": 9980,
  "size": 10010,
  "query": {
    "match_all": {}
  }
}
{
        "type": "illegal_argument_exception",
        "reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [19990]. 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."
}

对于此类问题,Elasticsearch Search为我们提供了一个与springBoot集成的强大依赖ElasticsearchRestTemplate,可以参考官方的 API 文档:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.9/java-rest-high-search-scroll.html

尝试使用解决问题:

public void scrollSearch() {
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withSort(new FieldSortBuilder("id").order(SortOrder.DESC))//排序
                .build();
                
        nativeSearchQuery.setMaxResults(1000);
    
        long scrollTimeOut = 60 * 1000;
        // 第一次查询
        SearchScrollHits<Book> searchScrollHits = elasticsearchRestTemplate.
                searchScrollStart(scrollTimeOut, query, Book.class, IndexCoordinates.of("ss.index.book"));

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

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

最后,感谢大家的聆听和阅读,我拿到了我期望的10000条以后的数据,

我以为我这次终于成功了,但我的麻烦才刚刚开始。

踩坑

该问题上线之后不久,一切都运行顺利,我以为已经高枕无忧的时候,我的麻烦再次来临。

用户侧反应了两个问题:

一、查询得时候发现有返回重复的数据。

二、从ES获取后上传数据发生了数据堆积。

查看日志,发现有大量的报错,报错信息表示存放的 scroll_id 超出了默认的500限制。

scroll api,JavaWeb编程,java

trying to creat too many scroll aontexts。Must be less than or equal to: [500].This limit can be set by changing the [search.max_open_scroll_context] setting.

因此我对问题做出以下分析

1、虽然进行 scroll 查询时会记录一个 scroll_id,但只有新请求时才会生成新的 scroll_id,这就有一定概率导致查询到的返回结果出现重复数据的可能。

2、scroll 开启时间过长,导致 scroll_id 的清除时间太久产生堆积,所以引起了数据查询延迟,引起了数据堆积。

这次由于我认真读取了报错信息,但我不愿以牺牲上限为代价,不然那将是无底洞式的调大上限,于是我在原先代码基础上做出了修改:

    public void scrollSearch() {
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withSort(new FieldSortBuilder("id").order(SortOrder.DESC))//排序
                .build();

        nativeSearchQuery.setMaxResults(1000);

        long scrollTimeOut = 60 * 1000;
        // 第一次查询
        SearchScrollHits<Book> searchScrollHits = elasticsearchRestTemplate.searchScrollStart(scrollTimeOut, query, Book.class, IndexCoordinates.of("ss.index.book"));
        
        //记录新请求
        SearchScrollHits<Book> newHits;

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

            for (SearchHit<Book> searchHit : searchScrollHits.getSearchHits()) {
                Book book = searchHit.getContent();
            }
            // 再次查询
            try {
                newHits = elasticsearchRestTemplate.searchScrollContinue(searchScrollHits.getScrollId(), scrollTimeInMillis, Book.class, IndexCoordinates.of("ss.index.book"));
                searchScrollHits = newHits;
            } finally {
                elasticsearchRestTemplate.searchScrollClear(Lists.newArrayList(searchScrollHits.getScrollId()));
            }
        }
    }

这样,我每次发出查询请求获得数据之后,都会清除掉上一次生成的scroll_id,如此保证scroll_id不会超出500;

不出意外的,我又出意外了,显然我在对scroll_id理解上出了问题,它不是对每页的标记,而是每一次滚动查询整个生命周期的唯一id,上述代码导致的结果就是我永远只能拿到前两页的内容,之后因为找不到生命周期的唯一id报错。
scroll api,JavaWeb编程,java

最终解决

那么最终导致scroll_id堆积的原因也找到了:searchScrollStart入参从来都不是什么TimeOut时间,而是scroll_id存在的生命周期时间,如果这个时间过大,那么scroll_id就得不到及时清理,最终超过500进而报错,解决方案就会有两种:

1.根据实际每次请求的调用需求时间,调整scroll_id的生命周期,保持在一个合适的时间,从而防止堆积

2.动态清理scroll_id

显然第一种是在难为我胖虎,我选择了第二种,将searchScrollStart视为一次滚动查询请求的开始,searchScrollHits.hasSearchHits()为false时视为结束,此时searchScrollClear在合适不过。

第三次修改:

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

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

至此,才是真正的谢谢大家的阅读啦~~~good bye!文章来源地址https://www.toymoban.com/news/detail-816852.html

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

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

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

相关文章

  • ES scroll查询的坑点

    scroll 查询是ES中为了解决一次获取不到全部数据的一种解决方案。 第一次查询 第二次查询(第二次查询,可以不加scroll的失效时间) 第2+n次访问(第三次及之后的查询必须要加scroll的失效时间) 首次访问 访问后,会得到部分或全部数据和scroll_id. 之后再访问 注意点 : 用

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

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

    2024年02月03日
    浏览(69)
  • 关于uniapp微信小程序scroll-view组件使用show-scrollbar隐藏不了滚动条

    这里关于使用  scroll-view组件  时候有滚动条 想要隐藏滚动条但是使用show-scrollbar没有效果 这时候又使用类名隐藏滚动条 使用id隐藏滚动条都不行 解决方法:在使用  scroll-view组件 的页面或者app 页面加上以下代码就可以了         

    2024年02月12日
    浏览(30)
  • Java ES 滚动查询

    滚动查询(Scroll Query)是 Elasticsearch 提供的一种机制,用于处理大量数据的查询。它允许你在多个请求之间保持“游标”,以便在后续请求中获取更多的结果。 以下是滚动查询的基本工作原理: 1 初始查询: 客户端发送一个查询请求给 Elasticsearch,并指定一个滚动时间(scro

    2024年02月08日
    浏览(29)
  • es滚动查询分析和使用步骤

    ES在进行普通的查询时,默认只会查询出来10条数据。我们通过设置es中的size可以将最终的查询结果从10增加到10000。如果需要查询数据量大于es的翻页限制或者需要将es的数据进行导出又当如何? Elasticsearch提供了一种称为\\\"滚动查询\\\"(Scrolling)的机制,用于处理大型数据集的分

    2024年02月09日
    浏览(23)
  • Elasticsearch“滚动查询“(Scrolling)的机制的与Java使用ES Client 调用滚动查询

    ES在进行普通的查询时,默认只会查询出来10条数据。我们通过设置es中的size可以将最终的查询结果从10增加到10000。如果需要查询数据量大于es的翻页限制或者需要将es的数据进行导出又当如何? Elasticsearch提供了一种称为 \\\"滚动查询\\\"(Scrolling) 的机制,用于处理大型数据集的

    2024年02月11日
    浏览(33)
  • ElasticSearch第六讲 ES 三种分页查询from+size / Scroll /search_after

    我的Git地址:https://gitee.com/ITLULU 欢迎访问 ES的分页查询和关系数据库的分页查询的区别: ES分页查询有以下几种: 1:简单的 from size (有默认的最大Size,不可无限大小查询,因为数据过多查询性能会降低,且也要考虑内存问题,以及OS缓存数据的能力) 2: scroll基于查询窗口

    2024年02月01日
    浏览(39)
  • 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日
    浏览(29)
  • es Elasticsearch 六 java api spirngboot 集成es

    目录 Java restApi Springboot 集成es 新增-同步 新增-异步 增删改查流程 _bulk 批量操作 新增-同步 新增-异步 增删改查流程 创建请求、2.执行、3.查看返回结果     _bulk 批量操作 ok 持续更新

    2024年02月10日
    浏览(41)
  • ES es Elasticsearch 十三 Java api 实现搜索 分页查询 复杂查询 过滤查询 ids查询 等

    目录 Java api 实现搜索 Pom.xml 建立链接 搜索全部记录 增加规则值查某些字段 搜索分页 全代码 Ids 搜索 搜索Match搜索 multi_match 搜索 多字段搜索 复杂查询 bool查询 filter  bool 复杂查询增加过滤器查询 复杂擦好像加排序 日志 思路 参考 api 写法 写Java代码 请求条件构建层次

    2024年02月04日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包