gpt4 book ai didi

performance - 具有高基数字段的 ElasticSearch 术语和基数性能

转载 作者:行者123 更新时间:2023-12-02 22:30:03 26 4
gpt4 key购买 nike

TL;博士

与 SQL Server 上的相同查询相比,我的 ElasticSearch 查询需要很长时间。
难道我做错了什么?有什么方法可以提高我的查询性能?
它只是 RDBMS 比 NoSQL 做得更好的事情之一吗?

前提

假设我有一家接受订单并交付所需元素的企业。

  • 我想知道每个订单的平均独特商品数量。
  • 我的订单数据按订购的每件商品排列 - 每个订单都有一条或多条记录,其中包含订单 ID、商品 ID 等。
  • 我有一个用于开发目的的单节点设置
  • 无论我有 4 GB 堆空间(在 12 GB 机器上)还是 16 GB 堆空间(在 32 GB 机器上),结果(性能方面)都是相同的
  • 该索引有数十亿条记录,但查询将其过滤为大约 300,000 条记录
  • 订单和商品 ID 属于关键字类型(本质上是文本),我无法更改它。
  • 在这种特殊情况下,平均独特商品数为 1.65 - 许多订单仅包含一件独特商品,其他订单包含 2 件,少数包含多达 25 件独特商品。

  • 问题

    使用 ElasticSearch,我将不得不使用术语聚合按订单 ID 对文档进行分组,使用基数聚合来获得唯一项目数,并使用平均桶聚合来获得每个订单的平均项目数。

    这在我的两个设置中都需要大约 23 秒。在 SQL Server 上使用相同的数据集进行相同的查询不到 2 秒。

    附加信息

    Elasticsearch 查询
    {
    "size":0,
    "query":{
    "bool":{
    "filter":[
    {
    ...
    }
    ]
    }
    },
    "aggs":{
    "OrdersBucket":{
    "terms":{
    "field":"orderID",
    "execution_hint":"global_ordinals_hash",
    "size":10000000
    },
    "aggs":{
    "UniqueItems":{
    "cardinality":{
    "field":"itemID"
    }
    }
    }
    },
    "AverageItemCount":{
    "avg_bucket":{
    "buckets_path":"OrdersBucket>UniqueItems"
    }
    }
    }
    }

    起初,我的查询生成了 OutOfMemoryException,导致我的服务器停机。
    在我更高的 ram 设置上发出相同的请求会产生以下断路器:

    [request] Data too large, data for [<reused_arrays>] would be
    [14383258184/13.3gb], which is larger than the limit of
    [10287002419/9.5gb]


    ElasticSearch github 在这个问题上有几个(当前) Unresolved 问题:

    Cardinality aggregation should not reserve a fixed amount of memory per bucket #15892

    global_ordinals execution mode for the terms aggregation has an adversarially impact on children aggregations that expect dense buckets #24788

    Heap Explosion on even small cardinality queries in ES 5.3.1 / Kibana 5.3.1 #24359

    所有这些都导致我使用执行提示“global_ordinals_hash”,它允许查询成功完成(尽管需要时间..)

    类比 SQL 查询
    SELECT AVG(CAST(uniqueCount.amount AS FLOAT)) FROM 
    ( SELECT o.OrderID, COUNT(DISTINCT o.ItemID) AS amount
    FROM Orders o
    WHERE ...
    GROUP BY o.OrderID
    ) uniqueCount

    正如我所说,这非常非常快。

    orderID 字段映射
    {
    "orderID":{
    "full_name":"orderID",
    "mapping":{
    "orderID":{
    "type":"keyword",
    "boost":1,
    "index":true,
    "store":false,
    "doc_values":true,
    "term_vector":"no",
    "norms":false,
    "index_options":"docs",
    "eager_global_ordinals":true,
    "similarity":"BM25",
    "fields":{
    "autocomplete":{
    "type":"text",
    "boost":1,
    "index":true,
    "store":false,
    "doc_values":false,
    "term_vector":"no",
    "norms":true,
    "index_options":"positions",
    "eager_global_ordinals":false,
    "similarity":"BM25",
    "analyzer":"autocomplete",
    "search_analyzer":"standard",
    "search_quote_analyzer":"standard",
    "include_in_all":true,
    "position_increment_gap":-1,
    "fielddata":false
    }
    },
    "null_value":null,
    "include_in_all":true,
    "ignore_above":2147483647,
    "normalizer":null
    }
    }
    }
    }

    我设置了 eager_global_ordinals 试图提高性能,但无济于事。

    样本文件
    {
    "_index": "81cec0acbca6423aa3c2feed5dbccd98",
    "_type": "order",
    "_id": "AVwpLZ7GK9DJVcpvrzss",
    "_score": 0,
    "_source": {
    ...
    "orderID": "904044A",
    "itemID": "23KN",
    ...
    }
    }

    为了简洁和不公开的内容,删除了不相关的字段

    样本输出
    {
    "OrdersBucket":{
    "doc_count_error_upper_bound":0,
    "sum_other_doc_count":0,
    "buckets":[
    {
    "key":"910117A",
    "doc_count":16,
    "UniqueItems":{
    "value":16
    }
    },
    {
    "key":"910966A",
    "doc_count":16,
    "UniqueItems":{
    "value":16
    }
    },
    ...
    {
    "key":"912815A",
    "doc_count":1,
    "UniqueItems":{
    "value":1
    }
    },
    {
    "key":"912816A",
    "doc_count":1,
    "UniqueItems":{
    "value":1
    }
    }
    ]
    },
    "AverageItemCount":{
    "value":1.3975020363833832
    }
    }

    任何帮助将不胜感激:)

    最佳答案

    显然 SQL Server 在缓存这些结果方面做得很好。
    进一步调查显示,初始查询与 ElasticSearch 所用的时间相同。

    我将研究为什么这些结果没有通过 ElasticSearch 正确缓存。

    我还设法将订单 ID 转换为整数,这极大地提高了性能(尽管与 SQL Server 的性能提升相同)。

    另外,as advised by Mark Harwood on the Elastic Forum ,在基数聚合上指定precision_threshold 大大降低了内存消耗!

    所以答案是,对于这种特定类型的查询,ES 的性能至少与 SQL Server 一样好。

    关于performance - 具有高基数字段的 ElasticSearch 术语和基数性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44225038/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com