5.1.9. 百分位数聚合

未匹配的标注

百分位数聚合

多值度量标准聚合,可对从聚合文档中提取的数值计算一个或多个百分位数。这些值可以从文档中的特定数字字段中提取,也可以由提供的脚本生成。

百分位数表示观察值出现一定百分比的点。例如,第95个百分位数是大于观察值的95%的值。

百分位数通常用于查找异常值。在正态分布中,第0.13和第99.87个百分位数代表与平均值的三个标准差。任何超出三个标准偏差的数据通常被视为异常。

当检索到一定范围的百分位数时,它们可以用于估计数据分布并确定数据是否偏斜,双峰等。

假设您的数据包含网站加载时间。对于管理员来说,平均加载时间和中值加载时间并不是特别有用。最大值可能变的很出乎意料,它很容易被单一的缓慢响应所扭曲。

让我们看一下代表加载时间的百分比范围:

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time" 
            }
        }
    }
}
  1. load_time字段类型必须是数字

默认情况下,百分比度量标准将生成一定范围的百分比:[1,5,25,50,75,95,99]。响应将如下所示:

{
    ...

   "aggregations": {
      "load_time_outlier": {
         "values" : {
            "1.0": 5.0,
            "5.0": 25.0,
            "25.0": 165.0,
            "50.0": 445.0,
            "75.0": 725.0,
            "95.0": 945.0,
            "99.0": 985.0
         }
      }
   }
}

如您所见,聚合将返回默认范围内每个百分位的计算值。如果我们假设响应时间以毫秒为单位,那么很明显,该网页通常会在10-725ms内加载,但偶尔会激增至945-985ms。

通常,管理员只对异常值(极端百分比)感兴趣。我们可以只指定我们感兴趣的百分比(请求的百分比必须是介于0到100之间的一个值):

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "percents" : [95, 99, 99.9] 
            }
        }
    }
}
  1. 使用percents参数指定要计算的特定百分位数

Keyed 控制

默认情况下,keyed标志设置为true,该标志将唯一的字符串键与每个存储桶相关联,并将范围作为哈希而不是数组返回。将keyed标志设置为false将禁用此行为:

GET latency/_search
{
    "size": 0,
    "aggs": {
        "load_time_outlier": {
            "percentiles": {
                "field": "load_time",
                "keyed": false
            }
        }
    }
}

响应:

{
    ...

    "aggregations": {
        "load_time_outlier": {
            "values": [
                {
                    "key": 1.0,
                    "value": 5.0
                },
                {
                    "key": 5.0,
                    "value": 25.0
                },
                {
                    "key": 25.0,
                    "value": 165.0
                },
                {
                    "key": 50.0,
                    "value": 445.0
                },
                {
                    "key": 75.0,
                    "value": 725.0
                },
                {
                    "key": 95.0,
                    "value": 945.0
                },
                {
                    "key": 99.0,
                    "value": 985.0
                }
            ]
        }
    }
}

脚本

百分位数指标支持脚本。例如,如果我们的加载时间以毫秒为单位,但是我们希望以秒为单位计算百分位数,则可以使用脚本即时转换它们:

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "script" : {
                    "lang": "painless",
                    "source": "doc['load_time'].value / params.timeUnit", 
                    "params" : {
                        "timeUnit" : 1000   
                    }
                }
            }
        }
    }
}
  1. 用脚本参数替换field参数,该脚本参数使用脚本生成在其上计算百分位数的值

  2. 脚本支持参数化输入,就像其他任何脚本一样

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "script" : {
                    "id": "my_script",
                    "params": {
                        "field": "load_time"
                    }
                }
            }
        }
    }
}

百分位数(通常)是近似值

有许多不同的算法可以计算百分位数。理想中实现只是将所有值存储在一个排序数组中。即要找到第50个百分位数,您只需找到my_array [count(my_array)* 0.5]的值即可。

显然,理想中的实现是不可伸缩的 — 排序后的数组随数据集中值的数量线性增长。为了计算一个 Elasticsearch 集群中可能有数十亿个值的百分位数,需要计算近似百分位数。

百分位数度量使用的算法称为 TDigest (由Ted Dunning引入在 Computing Accurate Quantiles using T-Diges...)

使用此指标时,需要牢记一些准则:

  • 准确度与q(1-q)成正比。这意味着极端百分位数(例如99%)比不那么极端百分位数(例如中位数)更准确
  • 对于较小的一组值,百分位数非常准确(如果数据足够小,则可能为100%准确)。
  • 随着存储桶中值数量的增加,算法开始近似百分位数。它有效地交易了准确性以节省内存。确切的准确度级别很难一概而论,因为它取决于您的数据分布和要聚合的数据量

下表显示了一个均匀分布的相对误差,它取决于收集值的数量和请求的百分位数:

Percentiles Aggregation

它说明了对于极端百分位数来说,精度是如何更好。对于大量的值,误差减小的原因是大数定律使得值的分布越来越均匀,t-digest树可以更好地对其进行汇总。对于更倾斜的分布,则不会出现这种情况。

压缩

近似算法必须在存储器利用率与估计精度之间取得平衡。可以使用compression参数来控制:

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "tdigest": {
                  "compression" : 200 
                }
            }
        }
    }
}
  1. 压缩控制内存使用和近似误差

TDigest算法使用多个”节点”来近似百分位数-可用节点越多,与数据量成正比的精度(以及较大的内存占用量)就越高。compression参数将最大节点数限制为20 * compression

因此,通过增加压缩值,可以以更多内存为代价来提高百分位数的准确性。较大的压缩值也会使算法变慢,因为基础树数据结构的大小会增加,从而导致操作成本更高。默认压缩值为100

一个”节点”大约使用32个字节的内存,因此在最坏的情况下(按顺序到达并排序的大量数据),默认设置将产生大约 64KB 的 TDigest 大小。实际上,数据趋向于更加随机,并且 TDigest 将使用更少的内存。

HDR 直方图

注意:此设置公开了HDR直方图的内部实现,语法将来可能会更改。

HDR 直方图 (高动态范围直方图)是一种替代实现,在计算延迟测量的百分位数时会很有用,因为它比使用 t-digest 实现的速度更快在更大的内存占用量之间进行权衡。此实现维护一个固定的最坏情况百分比错误(指定为多个有效数字)。这意味着,如果在设置为3个有效数字的直方图中以1微秒至1小时(3,600,000,000微秒)的值记录数据,则对于1毫秒和3.6秒(或更佳)的值,它将保持1微秒的值分辨率)以获取最大跟踪值(1小时)。

可以通过在请求中指定method参数来使用HDR直方图:

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "percents" : [95, 99, 99.9],
                "hdr": { 
                  "number_of_significant_value_digits" : 3 
                }
            }
        }
    }
}
  1. hdr 对象指示应使用HDR直方图来计算百分位数,并且可以在对象内部指定此算法的特定设置
  1. number_of_significant_value_digits 指定有效位数的直方图值的分辨率

HDRHistogram 仅支持正值,如果传递负值,则将出错。如果值的范围未知,则使用 HDRHistogram 也不是一个好主意,因为这可能会导致大量内存使用。

缺失值

missing参数定义应如何处理缺少值的文档。默认情况下,它们将被忽略,但也可以将它们视为具有值。

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "grade_percentiles" : {
            "percentiles" : {
                "field" : "grade",
                "missing": 10 
            }
        }
    }
}
  1. grade字段中没有值的文档将与具有值10的文档归入同一存储桶。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
上一篇 下一篇
CrazyZard
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~