0%

ElasticSearch-聚合的精准度问题

相关阅读:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/search-aggregations-bucket-terms-aggregation.html

1. 分布式系统的近似统计算法

在分布式系统中,数据量、精确度和实时性三个指标只能同时满足其中两个。比如在数据量比较大的情况下,为了保证数据的实时性,那么就需要采用近似计算来提高实时性从而丢失了数据的精确度。

2. Terms 精度问题

ES 在进行聚合分析时同样也存在精度丢失的问题,下图是聚合分析的执⾏流程:

当 ES 数据量较大时,数据需要存放在不同节点的分片上,假设现在数据存放在 node1、node2 和 node3 三个节点分片上,那么要获取文档数最大的前三个数据时,其执行流程是先从三个节点分片上先分别获取最大的三个数据,然后在 coordinating nodes 上从 9 个数据再获取前三个最大的数据,并返回。但是这并不能保证结果正确。

比如下述示例中,ES 中共存放 12 条 A 记录,6 条 B 记录,5 条 C 记录和 6 条 D 记录,其按下图规则存放在不同的节点上。为了获取前三个文档数最大的记录,第一个节点会返回 A(6) / B(4) / C(4),第二个节点则返回 A(6) / B(2) / D(3),那么再次基础上最终结果将会返回 A(12) / B(6) / C(4)。但显然,正确的结果应该是 A(12) / B(6) / D(3)

在 Terms Aggregation 的返回中有两个特殊的数值:

  • doc_count_error_upper_bound : 被遗漏的 term 分桶,包含的⽂档,有可能的最⼤值
  • sum_other_doc_count: 除了返回结果 bucket 的 terms 以外,其他 terms 的⽂档总数(总数-返回的总数)

3. Terms 精度问题处理

Terms 聚合分析不准的原因,数据分散在多个分⽚上, Coordinating Node ⽆法获取数据全貌。有两种处理方案:

  • 当数据量不⼤时,设置 Primary Shard 为 1,实现准确性
  • 在分布式数据上,设置 shard_size 参数,提⾼精确度,原理即是每次从 Shard 上额外多获取数据,提升准确率。

比如我们现在新建一个索引 my_flights,并将其分片设定为 20:

然后将 kibana 自带的索引 kibana_sample_data_flights 的数据导入到 my_flights 中:

1
2
3
4
5
6
7
8
9
POST _reindex
{
"source": {
"index": "kibana_sample_data_flights"
},
"dest": {
"index": "my_flights"
}
}

下述 DSL 检索语句对字段 OriginWeather 进行分桶,并指定 shard_size 的值为 1,且打开开关 show_term_doc_count_error,以此我们便能观察到每个分桶中被遗漏的 term 分桶数量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET my_flights/_search
{
"size": 0,
"aggs": {
"weather": {
"terms": {
"field":"OriginWeather",
"size":5,
"shard_size": 1,
"show_term_doc_count_error": true
}
}
}
}

响应如下:

通过增加 shard_size 的值,我们便可以提高 terms 的数据准确度,例如当 shard_size 的值为 10 时,此时 doc_count_error_upper_bound 的值为 0,此时就表示数据是准确的。

调整 shard size ⼤⼩,可以降低 doc_count_error_upper_bound 来提升准确度,会增加整体计算量,提⾼了准确度,但会降低相应时间。

Shard Size 默认⼤⼩设定符合 shard size = size *1.5 +10

------ 本文结束------