• 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)

  • 相关阅读:
    xtoi (Hex to Integer) C function Nanoseconds Network
    Learning Scrapy | 王晨的博客
    Facebook搜索项目多名工程师均来自Google
    Beyond the C++ Standard Library: An Introduction to Boost: Björn Karlsson: 9780321133540: Amazon.com: Books
    归并排序 详解
    NewsFeed 3.0 发布,移植到 Python 3 开源中国 OSChina.NET
    对于拷贝构造函数和赋值构造函数的理解
    python 的os.fork()
    Install C++ Boost on Ubuntu
    石川的blog ,注意
  • 原文地址:https://www.cnblogs.com/small-k/p/8722792.html
Copyright © 2020-2023  润新知