首页 > 其他分享 >elasticsearchClient查询集合数据,过大的处理情况

elasticsearchClient查询集合数据,过大的处理情况

时间:2024-08-31 13:47:09浏览次数:3  
标签:search scrollId elasticsearchClient after hits 查询 过大 size

如果你不知道实际的记录数,并且想查询某个条件下的所有记录,可以使用以下两种方法来实现:滚动(scroll)查询search_after。这两种方法都适用于返回大量数据的场景。

方法一:滚动(Scroll)查询

Scroll 查询是一种有效获取大量数据的方式,特别是当你不知道要查询的记录数量时。Scroll 查询会在服务器端创建一个持久的快照,允许你逐步读取完整的结果集。

使用滚动查询的示例

import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.ScrollRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.ScrollResponse;

import java.util.ArrayList;
import java.util.List;

public List<KnowFileEs> searchAllRecords(String knowFileIndex, String knowFileId) {
    List<KnowFileEs> allResults = new ArrayList<>();
    
    // 初始搜索请求,设置scroll参数
    SearchResponse<KnowFileEs> searchResponse = elasticsearchClient.search(s -> s
            .index(knowFileIndex)
            .query(q -> q.term(t -> t.field("knowFileId").value(knowFileId)))
            .sort(so -> so.field(f -> f.field("id").order(SortOrder.Asc)))
            .size(100) // 设置每次返回的数量
            .scroll("1m"), // 设置scroll上下文有效时间
        KnowFileEs.class);

    // 获取初始的scrollId
    String scrollId = searchResponse.scrollId();

    // 处理初始响应
    searchResponse.hits().hits().forEach(hit -> allResults.add(hit.source()));

    while (searchResponse.hits().hits().size() > 0) {
        // 使用scrollId继续滚动请求
        ScrollResponse<KnowFileEs> scrollResponse = elasticsearchClient.scroll(s -> s
            .scrollId(scrollId)
            .scroll("1m"), // 同样的scroll上下文有效时间
            KnowFileEs.class);

        // 更新scrollId
        scrollId = scrollResponse.scrollId();

        // 处理滚动响应
        scrollResponse.hits().hits().forEach(hit -> allResults.add(hit.source()));
    }

    // 最后清除scroll
    elasticsearchClient.clearScroll(c -> c.scrollId(scrollId));

    return allResults;
}

代码解释

  1. 初始搜索请求:通过设置 scroll 参数来初始化滚动查询,并设定每批次返回的记录数量(例如 100 条)。

  2. 滚动查询 ID:Elasticsearch 返回的初始响应包含一个 scrollId,用来在后续的滚动请求中标识这个查询会话。

  3. 循环滚动请求:在 while 循环中,使用 scrollId 继续请求直到返回的记录数为 0(即没有更多记录)。

  4. 清除 Scroll 上下文:使用完滚动查询后,调用 clearScroll() 清除服务器端的滚动上下文。

方法二:使用 search_after

search_after 方法更适用于高效的分页查询,它使用上一次查询结果的最后一个文档的排序值作为下一个查询的起点,确保查询结果不会漏掉或重复。

使用 search_after 的示例

import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;

import java.util.ArrayList;
import java.util.List;

public List<KnowFileEs> searchAllRecords(String knowFileIndex, String knowFileId) {
    List<KnowFileEs> allResults = new ArrayList<>();
    List<Object> lastSortValues = null;
    boolean hasMoreHits = true;
    
    while (hasMoreHits) {
        SearchResponse<KnowFileEs> searchResponse = elasticsearchClient.search(s -> s
                .index(knowFileIndex)
                .query(q -> q.term(t -> t.field("knowFileId").value(knowFileId)))
                .sort(so -> so.field(f -> f.field("id").order(SortOrder.Asc)))
                .size(100) // 每批次返回的数量
                .searchAfter(lastSortValues), // 使用上一次最后一个文档的排序值作为下一次的起点
            KnowFileEs.class);
        
        List<Hit<KnowFileEs>> hits = searchResponse.hits().hits();
        if (hits.isEmpty()) {
            hasMoreHits = false;
        } else {
            hits.forEach(hit -> allResults.add(hit.source()));
            lastSortValues = hits.get(hits.size() - 1).sort(); // 获取最后一个文档的排序值
        }
    }
    
    return allResults;
}

代码解释

  1. 分页搜索请求:每次请求获取 100 条记录。

  2. 使用 search_after:每次查询时使用上一个批次结果的最后一个文档的排序值 (sort 值) 作为 search_after 参数。

  3. 循环处理:不断重复查询直到没有更多的记录返回。

选择方法的考虑

  • Scroll 查询:适合一次性读取大量数据,但会占用更多的内存资源(因为它在服务器端保持一个持久的快照)。适合需要导出大量数据或进行批量处理的场景。
  • search_after:更适合实时数据查询和分页显示,性能更好(不需要在服务器端维护一个大的快照)。适合分页浏览或需要低延迟的应用场景。

根据具体需求和使用场景选择适合的查询方式。如果只是临时性查询所有数据,Scroll 更为方便;而对于长期运行的应用,search_after 是更好的选择。


在 Elasticsearch 中,没有直接返回所有记录的简单方法,因为默认情况下,它有分页限制(一次最多返回 10,000 条记录)。这是一种防止服务器负载过高和客户端内存溢出的安全机制。Elasticsearch 旨在通过分页、scroll 查询或 search_after 查询等方式进行数据获取和处理。

然而,有一种方式可以“模拟”直接返回所有记录,即通过设置一个较大的 size 参数值。但这种方式只能用于小规模数据集,因为在 Elasticsearch 中,每个查询的 size 参数有一个硬限制(默认最多为 10,000)。因此,如果你的数据集非常大,下面的方法可能不适用。

方法:使用大的 size 参数

如果你确定数据集不会超过 10,000 条记录,并且你的 Elasticsearch 集群性能可以承受较大的内存和计算负载,你可以使用 size 参数来请求所有数据。

示例代码

SearchResponse<KnowFileEs> search = elasticsearchClient.search(s -> s
                .index(knowFileIndex)
                .query(q -> q.term(t -> t.field("knowFileId").value(knowFileId)))
                .sort(so -> so.field(f -> f.field("id").order(SortOrder.Asc)))
                .size(10000)  // 设置一个较大的 size 值
            , KnowFileEs.class);

代码解释

  1. size(10000):尝试获取最多 10,000 条记录。这是 Elasticsearch 的默认硬限制。

注意事项

  • 性能影响:请求一个较大的 size 值(例如 10,000)可能会消耗大量内存和处理时间,尤其是在数据集大、文档复杂或索引存储配置较低的情况下。
  • 数据限制:这种方法仅适用于数据集较小的情况。对于大型数据集(超过 10,000 条记录),你需要使用 scrollsearch_after 查询。

如果数据集较大(超过 10,000 条)

当数据量超过 10,000 条时,你应使用前面提到的 scroll 查询或 search_after 方法来获取所有记录。

  1. Scroll 查询:适合需要获取大量数据的场景,例如数据备份、批量处理等。
  2. search_after:适合分页查询场景,它使用排序值来获取下一页的结果,适用于低延迟需求的实时应用程序。

总结

  • 对于小数据集(小于 10,000 条记录),你可以通过设置较大的 size 参数来尝试获取所有数据。
  • 对于大数据集(超过 10,000 条记录),应使用 scrollsearch_after 查询方式。

Elasticsearch 的设计旨在高效地处理大规模数据,使用分页、滚动、或 search_after 是最佳实践,确保系统性能和稳定性。

标签:search,scrollId,elasticsearchClient,after,hits,查询,过大,size
From: https://www.cnblogs.com/haozai820/p/18390202

相关文章

  • Mysql基础练习题 596.查询至少有5个学生的所有班级 (力扣)
    596.查询至少有5个学生的所有班级建表插入数据:CreatetableIfNotExistsCourses(studentvarchar(255),classvarchar(255))TruncatetableCoursesinsertintoCourses(student,class)values('A','Math')insertintoCourses(student,class)values(......
  • RouteLLM:通过智能查询路由优化 AI 响应
    在当今人工智能驱动的世界中,优化人工智能的使用至关重要。不同的AI系统在能力和成本上各不相同,因此需要智能管理解决方案。RouteLLM是一个创新的框架,旨在动态地将用户查询路由到最合适的AI模型,确保成本效益和高质量的响应。什么是RouteLLM?RouteLLM作为AI查询的流量......
  • 驾驭SQL的多表连接:解锁复杂查询的高级技巧
    驾驭SQL的多表连接:解锁复杂查询的高级技巧在数据库管理中,多表连接是处理关系型数据库中数据关联的一种强大工具。通过使用SQL的多表连接,可以合并来自多个表的数据,以提供更丰富的信息和深入的分析。本文将详细介绍如何使用SQL进行复杂的多表连接,并提供实际的代码示例,帮助你......
  • 【信息收集】网络空间测绘FOFA,查询语法最全使用方法(图文解析)
    高级搜索基础类别标记类(SpecialLabel)协议类(type=service)网站类(type=subdomain)证书类地理位置(Location)时间类(Lastupdatetime)独立IP语法(独立IP系列语法,不可和上面其他语法共用)查询基础语法案例html搜索title标题搜索domain域名搜索host主机名搜索o......
  • 推荐一款开源一站式SQL审核查询平台!功能强大、安全可靠!C5
    1、前言在当今这个数据驱动的时代,数据库作为企业核心信息资产的载体,其重要性不言而喻。随着企业业务规模的不断扩大,数据库的数量和种类也日益增多,这对数据库的管理与运维工作提出了前所未有的挑战。在这样的背景下,一款高效、易用的数据库管理工具显得尤为重要。Archery,作为一款开......
  • go语言DB通用查询实现解析
    用例funcTest018_QueryShop(t*testing.T){   vardbRequest=Default()   dbRequest.TableName="contact_shop"   dbRequest.SetPageSize(2).OrderByAsc("id")   dbRequest.FieldsName="id_10,id,name"   varresult=dbRequ......
  • [每日一练]查询结果的质量和占比(布尔值的灵活使用)
    题目来源于力扣:1211.查询结果的质量和占比-力扣(LeetCode)题目要求:Queries表:+-------------+---------+|ColumnName|Type|+-------------+---------+|query_name|varchar||result|varchar||position|int||rating|int......
  • 29:函数查询,添加,修改,删除
    #_*_coding:utf-8_*_importosdeffile_handle(filename,backend_data,record_list=None,type='fetch'):#type:fetchappendchangenew_file=filename+'_new'bak_file=filename+'_bak'iftype=='fetch':......
  • Taro 引入moment.js打包过大
    moment.js的包中有许多语言库,这些语言库比moment.js本身还大,再打包时也会一起打进去,但这些语言库很多情况下不会用到,所以可以手动将其无用的语言库删除掉。这里有一篇分析的文章 https://zhuanlan.zhihu.com/p/90306969 ,我使用了最没技术含量的操作就是删除多余的语言库。在......
  • pageHelper分页插件导致的查询慢的问题优化
    首先在yml中配置mybatis:configuration:log-impl:org.apache.ibatis.logging.stdout.StdOutImpl会进行sql语句打印问题:进行分页查询时pageHelper自动生成的count语句相当于在查询语句外包一层selectcount(1)from(你的查询语句)对于你的查询语句的返回条件中有较......