zoukankan      html  css  js  c++  java
  • es实战之查询大量数据

    背景

    项目中已提供海量日志数据的多维实时查询,客户提出新需求:将数据导出。

    将数据导出分两步:

    1. 查询大量数据
    2. 将数据生成文件并下载

    本文主要探讨第一步,在es中查询大量数据或者说查询大数据集。

    es支持的查询数量

    es默认支持的查询数量或者说查询深度是10,000。

    可以动态修改max_result_window这个参数的设置,默认为10,000。

    PUT xz-logs/_settings?preserve_existing=true
    {
      "index.max_result_window" : "10000000"
    }
    

    es search api

    from + size

    GET /_search
    {
        "from" : 0, "size" : 10,
        "query" : {
            "term" : { "user" : "kimchy" }
        }
    }
    

    当Elasticsearch响应请求时,它必须确定docs的顺序,全局排序响应结果。
    如果请求的页数较少时,假设每页10个docs——即pageSize=10, 此时Elasticsearch不会有什么问题。

    但若取的页数较大时(深分页),如请求第20页,Elasticsearch不得不取出所有分片上的第1页到第20页的所有docs,假设你有16个分片,则需要在coordinate node 汇总到 shards* (from+size)条记录,即需要 16*(20+10)记录后做一次全局排序,再最终取出 from后的size条结果作为最终的响应。

    所以:当索引非常非常大(千万或亿),是无法安装 from + size 做深分页的,分页越深则越容易OOM,即便不OOM,也是很消耗CPU和内存资源的。

    scroll

    scroll类似于数据库中的游标。

    游标查询允许我们 先做查询初始化,然后再批量地拉取结果。 这有点儿像传统数据库中的 cursor 。

    游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。 它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 视图 一样。

    深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段 _doc 来排序。 这个指令让 Elasticsearch 仅仅从还有结果的分片返回下一批结果。

    第一次查询

    GET /old_index/_search?scroll=1m 
    {
        "query": { "match_all": {}},
        "sort" : ["_doc"], 
        "size":  1000
    }
    

    第二次查询

    GET /_search/scroll
    {
        "scroll": "1m", 
        "scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs="
    }
    

    Scanning Scroll API

    如果只对查询结果感兴趣而不关心结果的顺序,可以使用更高效的scanning scroll。使用方法非常简单,只需在查询语句后加上“search_type=scan”即可。

    search after(5.0新特性)

    search_after is not a solution to jump freely to a random page but rather to scroll many queries in parallel. It is very similar to the scroll API but unlike it, the search_after parameter is stateless, it is always resolved against the latest version of the searcher. For this reason the sort order may change during a walk depending on the updates and deletes of your index.

    search_after类似于scroll,不同之处是:search_after是无状态的,它总是针对最新版本的搜索器进行解析。由于更新或者删除索引,搜索的排序结果可能会发生变化。

    bulk

    bulk是将多个请求合并成一个请求,如下所示:

    POST _bulk
    { "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
    { "field1" : "value1" }
    { "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
    { "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
    { "field1" : "value3" }
    { "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
    { "doc" : {"field2" : "value2"} }
    

    其他

    插件: elasticsearch-dataformat

    实际使用过程中,该插件不好用。如果带查询条件,数据无法导出。查看其依赖的jar包,估计其调用poi来生成csv文件, 估计速度快不了。

    这种插件做demo可以,实际生成中,不太敢使用,因为不可控因素太多。

    总结

    综上所述,最后采用scroll api来解决es查询大量数据的问题。不过数据量大一点,查询时间就比较长,在本人的集群中,查询10w条,需要将近1分钟的时间。(附本人集群:3个节点。每个节点配置为cpu 8核,heap size 16G,每个索引有5个分片、1个副本。数据量每天4500w)

  • 相关阅读:
    centos go语言 开启代理 国内镜像
    Docker给MongoDB设置用户密码
    ubuntu镜像一般apt-get源地址都是在国外导致在构建时因为源地址问题导致下载速度极其得慢
    在centos7安装nodejs并升级nodejs到最新版本
    使用express创建简单web服务器
    关于docker的mongo镜像的部署
    Python:函数定义
    Python:if-while-for
    Python:运算符
    Python:标准数据类型6种
  • 原文地址:https://www.cnblogs.com/small-k/p/8722792.html
Copyright © 2011-2022 走看看