jjzjj

ElasticSearch中Scroll查詢理解

唐三水 2023-10-23 原文

一、背景

管理後臺有個導出需求,一個Event的點擊日志,總數可能有個2-3W,但是客戶到出我們是

From -To 這之間的記錄數,超過1W 的數據倒不出來,縂條數顯示有2萬多,客戶需要到處隨意條數。這個大家都懂是ES的最大返回條數控制了;

網上查詢了方法有Scroll可以實現; 貌似Search After也可以實現

而我們剛好使用的 client是  RestHighLevelClient 有一些參考網頁是別的Clent已經過時了,此處就不做展示了【反正就是关联上你的Es的cluster等配置信息即可】

再完成了单元测试的改造之后发现Scroll并不支持from\size的翻页参数设置,此处需要注意

SearchRequest 【请求设置】 和 SearchResponse.[拿到结果]

SearchRequest  中的  SearchSourceBuilder 参数要去掉from入参,而builer原来分页的size变成了scroll滚动查询时的每个分片返回的条数 
    public SearchSourceBuilder getScrollSearchSourceBuilder() {
//        searchSourceBuilder.from(start); 
//        searchSourceBuilder.size(pagesize);
        searchSourceBuilder.size(5000);
        searchSourceBuilder.fetchSource(includes, excludes);
        if(this.distinctField!=null){
            searchSourceBuilder.collapse(new CollapseBuilder(this.distinctField));
        }
        if (highlightBuilder.fields().size() > 0) {
            highlightBuilder.preTags(preTags);
            highlightBuilder.postTags(postTags);
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        return searchSourceBuilder.query(boolQueryBuilder);
    }

具体滚动查询的实现接口

EsQuery中也可以防止Scroll对象,这里我是写到代码里了

public <T> EsResult<List<T>> createScrollSearch(EsIndexConstant index, EsQuery esQuery, Class<T> clazz) {
    SearchResponse result;
    SearchRequest search = new SearchRequest(index.name());
    search.source(esQuery.getScrollSearchSourceBuilder());
    //是否有路由
    if(StrUtil.isNotBlank(esQuery.getRouting())){
        search.routing("routing",esQuery.getRouting());
    }
    //滚动游标设置
    Scroll scroll = new Scroll(new TimeValue(600000));
    search.scroll(scroll);
    log.debug("Elasticsearch Exec:{}",search.source());
    int i = 0;
    while (true) {
        try {
            result = rhlClient.search(search,RequestOptions.DEFAULT);
            break;
        } catch (IOException e) {
            i++;
            log.error("elasticsearch createSearch,retry Count:{}, error :{}",i, e);
            if(i>retry){
                //超过重试次数,则抛出此异常
                throw ExceptionConstant.queryDataException(ExceptionCodeEnum.esQueryIoException, e);
            }
        }
    }
    if (!result.status().equals(RestStatus.OK)){
        log.error("elasticsearch search error");
        return new EsResult(false);
    }
    String scrollId = result.getScrollId();
    //返回集合
    List resultList = new ArrayList<>();
    //放入总条数
    SearchHits hits = result.getHits();
    //获取总数
    Long total = hits.getTotalHits().value;
    TotalHits.Relation esCount = hits.getTotalHits().relation;
    SearchHit[] hitsHits = hits.getHits();
    try {
        while(ArrayUtil.isNotEmpty(hitsHits)){
            if (clazz.equals(Map.class) || clazz.equals(Dict.class)) {
                for (SearchHit hitsHit : hitsHits) {
                    resultList.add(hitsHit.getSourceAsMap());
                }
            } else {
                for (SearchHit hitsHit : hitsHits) {
                    T entity = JSON.parseObject(hitsHit.getSourceAsString(), clazz, FastjsonUtil.parserConfig);
                    resultList.add(entity);
                }
            }
            //再次发送请求,并使用上次搜索结果的ScrollId
            SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
            searchScrollRequest.scroll(scroll);
            SearchResponse searchScrollResponse = rhlClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
            scrollId = searchScrollResponse.getScrollId();
            hitsHits = searchScrollResponse.getHits().getHits();
        }
        //及时清除es快照,释放资源
        ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
        clearScrollRequest.addScrollId(scrollId);
        rhlClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
    }catch (IOException e){
        log.error("elasticsearch scroll search error");
    }
    return new EsResult(resultList,true).total(total);
}

在fromSize 不能返回的事实不能实现 我才明白Scroll只能根据筛选条件滚动返回所有结果。

然后你需要哪些数据可以在ResultList中做相关逻辑处理。

还有没有别的弊端 暂时不知,还需进一步总结。 后续用一个searchAfter的接口实现 看看区别

由于我的这个索引数据一周变更一次,只会往里面写入数据,且在管理后台使用所以对实时性的要求不是那么高……

有关ElasticSearch中Scroll查詢理解的更多相关文章

  1. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  2. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  3. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  4. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  5. ruby - 如何理解 Ruby 中的发送者和接收者? - 2

    我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo

  6. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  7. ruby - Rails Elasticsearch 聚合 - 2

    不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a

  8. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  9. ruby-on-rails - 使用 Rails (Tire) 和 ElasticSearch 进行模糊字符串匹配 - 2

    我有一个Rails应用程序,现在设置了ElasticSearch和Tiregem以在模型上进行搜索,我想知道我应该如何设置我的应用程序以对模型中的某些索引进行模糊字符串匹配。我将我的模型设置为索引标题、描述等内容,但我想对其中一些进行模糊字符串匹配,但我不确定在何处进行此操作。如果您想发表评论,我将在下面包含我的代码!谢谢!在Controller中:defsearch@resource=Resource.search(params[:q],:page=>(params[:page]||1),:per_page=>15,load:true)end在模型中:classResource'Us

  10. ruby - 你如何理解 Ruby 中的这个三元条件? - 2

    我在某些代码中遇到了三元组,但我无法理解条件:str.split(/',\s*'/).mapdo|match|match[0]==?,?match:"somestring"end.join我确实理解我是在某些点上拆分字符串并将总结果转换为数组,然后依次处理数组的每个元素。除此之外,我不知道发生了什么。 最佳答案 一种(稍微)不那么令人困惑的写法是:str.split(/',\s*'/).mapdo|match|ifmatch[0]==?,matchelse"somestring"endend.join我认为多行三元语句很糟糕,尤其是

随机推荐