非常慢的弹性搜索术语聚合.如何提高?

pri*_*kha 6 aggregate query-performance elasticsearch

我们有〜20M(酒店提供)存储在弹性(1.6.2)文件,关键是要通过多个字段组文档(duration, start_date, adults, kids),然后选择一个便宜的报价了各组.我们必须按成本字段对这些结果进行排序.

为了避免子聚合,我们将目标字段值合并为一个default_group_field通过将它们与点(.)连接而调用的值.

该字段的映射如下所示:

  "default_group_field": {
    "index": "not_analyzed",
    "fielddata": {
      "loading": "eager_global_ordinals"
    },
    "type": "string"
  }
Run Code Online (Sandbox Code Playgroud)

我们执行的查询看起来像这样:

{
  "size": 0,
  "aggs": {
    "offers": {
      "terms": {
        "field": "default_group_field",
        "size": 5,
        "order": {
          "min_sort_value": "asc"
        }
      },
      "aggs": {
        "min_sort_value": {
          "min": {
            "field": "cost"
          }
        },
        "cheapest": {
          "top_hits": {
            "_source": {}
            },
            "sort": {
              "cost": "asc"
            },
            "size": 1
          }
        }
      }
    }
  },
  "query": {
    "filtered": {
      "filter": {
        "and": [
          ...
        ]
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

问题是此类查询需要几秒钟(2-5秒)才能加载.

但是,一旦我们执行没有聚合的查询,我们会"total": 490在100毫秒内获得适量的结果(比方说 ).

{
  "took": 53,
  "timed_out": false,
  "_shards": {
    "total": 6,
    "successful": 6,
    "failed": 0
  },
  "hits": {
    "total": 490,
    "max_score": 1,
    "hits": [...
Run Code Online (Sandbox Code Playgroud)

但是聚合需要2秒:

{
  "took": 2158,
  "timed_out": false,
  "_shards": {
    "total": 6,
    "successful": 6,
    "failed": 0
  },
  "hits": {
    "total": 490,
    "max_score": 0,
    "hits": [

    ]
  },...
Run Code Online (Sandbox Code Playgroud)

似乎不应该花这么长时间来处理适量的过滤文档并选择每组中最便宜的文档.它可以在应用程序内部完成,这对我来说似乎是一个丑陋的黑客攻击.

日志中充满了说明:

[DEBUG][index.fielddata.plain ] [Karen Page] [offers] Global-ordinals[default_group_field][2564761] took 2453 ms

这就是我们更新映射以在索引更新时执行热切的global_ordinals重建的原因,但这并没有对查询计时产生显着影响.

有没有办法加速这种聚合,或者可能是一种方法来告诉弹性只对过滤后的文档进行聚合.

或者可能还有另一个这么长的查询执行源?任何想法高度赞赏!

pri*_*kha 6

再次感谢你的努力.

最后我们解决了主要问题,我们的表现恢复正常.

简而言之,我们已经完成了以下操作: - 更新了default_group_field类型的映射Long - 压缩default_group_field值以使其匹配类型Long

一些解释:

字符串字段的聚合需要对它们进行一些工作.正如我们从日志中看到Global Ordinals的那样,具有非常广泛差异的那个领域非常昂贵.实际上,我们只对所提到的字段进行聚合.据说使用String类型效率不高.

所以我们将映射更改为:

default_group_field: {
  type: 'long',
  index: 'not_analyzed'
}
Run Code Online (Sandbox Code Playgroud)

这样我们就不会触及那些昂贵的操作.

在此之后,相同的查询时间减少到~100ms.它还降低了CPU使用率.

PS 1

我从全球序数的文档中获得了大量信息

PS 2

我仍然不知道如何绕过类型字段的这个问题String.如果你有什么想法,请评论.

  • RE: PS 2 - 如果您使用 String 类型,您可以通过急切地构建全局序数来提高性能 - https://www.elastic.co/guide/en/elasticsearch/reference/current/eager-global-ordinals.html和 https://alexmarquardt.com/how-to-tune-elasticsearch-for-aggregation-performance/ (2认同)