在es中用scroll查询与completableFuture

一般而言,es返回数据的上限是10000条,如果超过这个数量,就必须使用scroll查询。

所谓scroll查询就类似DBMS中的游标,或者快照吧,利用查询条件,在第一次查询时,在所有的结果上形成了一个快照,然后再分批分次的读取出来。

要完成一个scroll查询分两个阶段:

阶段一:带查询参数

1 POST /twitter/_search?scroll=1m
2 {
3     "size": 100,
4     "query": {
5         "match" : {
6             "title" : "elasticsearch"
7         }
8     }
9 }

这个查询条件比较简单,只是示意。

关键是有两点:1.post路径中的scroll关键字,指明是一个scroll查询;2,scroll=1m意味着查询结果数据在es的服务器有效期是一分钟。

在查询结果的返回值中会带有一个scroll id的参数,这个参数在第二次查询的时候需要。

阶段二:不带参数查询

POST  /_search/scroll
{
    "scroll" : "1m",
    "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}

这个查询请求中,会带上第一次请求得到的scroll_id这个字段。

然后循环往复,第三次查询需要带上第二次查询返回的scroll_id,以此类推,就这个例子而言,当判断返回的数据条数小于100条的时候,就可以结束请求了。

使用scroll查询的两个优势是:

1.无论查询的数据量是多大,都能够查询成功。

2.准确反映了第一次查询当时的查询结果,第一次查询之后的查询请求不会包含新的数据。

但也有一个缺点:

1.因为查询的递进的,第二次依赖于第一次,第三次依赖于第二次,所以如果数据量很多,查询的耗时就比较长。

如何解决耗时长这个问题了?就不能使用scroll来查询了,使用常规的查询,但是启用多线程去查。

GET /_search
{
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

加入在常规的查询中有timestamp这样的自动,我们可以预先对timestamp进行划分,比如分出10份,当然前提是我们假设数据在时间上是均匀的,然后每个时间切分启用一个线程去查询。在java中有completableFuture能够比较好的支持这种查询场景。

CompletableFuture<JSONArray>[] futures = (CompletableFuture<JSONArray>[]) new CompletableFuture[count];
                for (int i = 0; i < count; i++) {
                    CompletableFuture<JSONArray> future = CompletableFuture.
                            supplyAsync(new JSONAarrySupplier(this.queryString,timestamp[i])
                            .exceptionally(ex -> {
                                logger.error(ex.getMessage());
                                return null;});
                    futures[i] = future;
                }
                CompletableFuture<List<JSONArray>> allFuture = myAllOf(futures);
                result = allFuture.get();

如上述,在一开始建立了一个future数组,然后根据时间切片,构建查询请求,并放入completableFuture中。

在最后调用get方法,拿到所有线程执行完的结果。

这里有一个点要注意,就是completableFuture.allOf方法本身返回的是void,如果我们的future是有返回值的话,就不能直接调用java自身提供的,需要改下一下,如上其实调用了下面的方法:

 public static CompletableFuture<List<JSONArray>> myAllOf(CompletableFuture<?>... futures) {
        return CompletableFuture.allOf(futures)
                .thenApply(x -> Arrays.stream(futures)
                        .map(f -> (JSONArray) f.join())
                        .collect(toList())
                ).exceptionally(ex -> {
                    logger.error(ex.getMessage());
                    return null;});
    }

这个方法中实现了返回值的转换。

这种多线程的查询,相对于scroll去查询,在网络不是瓶颈的前提下,性能还是有很大提升。

综上所述:

1.如果对时间不敏感,还是推荐使用scroll查询,毕竟反映了查询时间点的实际情况。

2.如果对时间敏感,则需要合理挑选查询分片条件,形成合理的多线程查询。

参考https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html

原文地址:https://www.cnblogs.com/029zz010buct/p/9959917.html

时间: 2024-10-14 01:02:25

在es中用scroll查询与completableFuture的相关文章

es实战之查询大量数据

背景 项目中已提供海量日志数据的多维实时查询,客户提出新需求:将数据导出. 将数据导出分两步: 查询大量数据 将数据生成文件并下载 本文主要探讨第一步,在es中查询大量数据或者说查询大数据集. es支持的查询数量 es默认支持的查询数量或者说查询深度是10,000. 可以动态修改max_result_window这个参数的设置,默认为10,000. PUT xz-logs/_settings?preserve_existing=true { "index.max_result_window&qu

【转】ES的常用查询与聚合

原文地址:http://blog.51cto.com/xpleaf/2307572 0 说明 基于es 5.4和es 5.6,列举的是个人工作中经常用到的查询(只是工作中使用的是Java API),如果需要看完整的,可以参考官方相关文档https://www.elastic.co/guide/en/elasticsearch/reference/5.4/search.html. 1 查询 先使用一个快速入门来引入,然后后面列出的各种查询都是用得比较多的(在我的工作环境是这样),其它没怎么用的这里

es的基本查询api的使用

本文主要记录es的基本查询api的使用 基本查询种类 term查询 { "query": { "term": { "title": "crime" } } } 指定权重 { "query": { "term": { "title": { "value":"crime", "boost":10.0 } } }

SQL中的LIKE中用参数化查询

今天终于学会怎么在like中用参数化查询啦..哈哈..再也不用担心sql注入了...

order by中用子查询排序

今天有个需求是对一个列表排序,但是排序字段是在另一个表中,不想用关联查询,就想能否直接在order by中用子查询,后来找到一个还挺好使.记录如下. 排序语句如下: select * from mainpage_report_sum s where s.year_month = '2019-02' and s.orgid in (select * from (select id from SYS_ORGANIZATION_REPORT o order by o.org_order1 asc));

es多条件查询之must用法(Java实现)

package com.zx.znyd.es; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map;import org.apache.commons.lang.StringUtils; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import

ES开启慢查询日志

默认情况,慢日志是不开启的.要开启它,需要定义具体动作(query,fetch 还是 index),你期望的事件记录等级( WARN.INFO.DEBUG.TRACE 等),以及时间阈值. es有几种搜索模式,比如 query_then_fetch , 表示先从各个节点query到id,然后整合,再去各个节点拿具体数据 这是一个索引级别的设置,也就是说可以独立应用给单个或所有索引,这个配置是永久的,配置后即使集群重启也会保留 PUT /_all/_settings { "index.search

c#中用DataView查询

新人菜鸟 在开发一款软件,用到了 MyS中的 DataView 查询.查询后判断视图是否有返回值,找了好久,终于找到了他的 DataView XX.Count 参数. string table = String.Format("`Database` WHERE `XX` = '{0}';", XX); DataView dv = mysqlUtile.MysqlDataAdapter(table); if (dv.Count==0) { ... } } 原文网址:http://skyb

ES优化聚合查询之深度优先和广度优先

1.优化聚合查询示例 假设我们现在有一些关于电影的数据集,每条数据里面会有一个数组类型的字段存储表演该电影的所有演员的名字. { "actors" : [ "Fred Jones", "Mary Jane", "Elizabeth Worthing" ] } 如果我们想要查询出演影片最多的十个演员以及与他们合作最多的演员,使用聚合是非常简单的: { "aggs" : { "actors"