箱线图聚合
编辑箱线图聚合
编辑一个 boxplot
度量聚合,用于计算从聚合文档中提取的数值的箱线图。这些值可以从文档中的特定数值字段或直方图字段生成。
boxplot
聚合返回绘制箱线图 的必要信息:最小值、最大值、中位数、第一四分位数(第 25 个百分位数)和第三四分位数(第 75 个百分位数)的值。
语法
编辑单独的 boxplot
聚合看起来像这样:
{ "boxplot": { "field": "load_time" } }
让我们来看一个表示加载时间的箱线图:
resp = client.search( index="latency", size=0, aggs={ "load_time_boxplot": { "boxplot": { "field": "load_time" } } }, ) print(resp)
response = client.search( index: 'latency', body: { size: 0, aggregations: { load_time_boxplot: { boxplot: { field: 'load_time' } } } } ) puts response
const response = await client.search({ index: "latency", size: 0, aggs: { load_time_boxplot: { boxplot: { field: "load_time", }, }, }, }); console.log(response);
GET latency/_search { "size": 0, "aggs": { "load_time_boxplot": { "boxplot": { "field": "load_time" } } } }
响应将如下所示:
{ ... "aggregations": { "load_time_boxplot": { "min": 0.0, "max": 990.0, "q1": 167.5, "q2": 445.0, "q3": 722.5, "lower": 0.0, "upper": 990.0 } } }
在这种情况下,下须和上须的值等于最小值和最大值。通常,这些值是 1.5 * IQR 范围,也就是说,最接近 q1 - (1.5 * IQR)
和 q3 + (1.5 * IQR)
的值。由于这是一个近似值,因此给定的值可能实际上并非来自数据的观察值,但应在它们的合理误差范围内。虽然箱线图聚合不会直接返回异常值点,但您可以检查 lower > min
或 upper < max
是否存在来查看两侧是否存在异常值,然后直接查询它们。
脚本
编辑如果您需要为未精确索引的值创建箱线图,则应创建一个运行时字段 并获取该字段的箱线图。例如,如果您的加载时间以毫秒为单位,但您希望以秒为单位计算值,请使用运行时字段将其转换。
resp = client.search( index="latency", size=0, runtime_mappings={ "load_time.seconds": { "type": "long", "script": { "source": "emit(doc['load_time'].value / params.timeUnit)", "params": { "timeUnit": 1000 } } } }, aggs={ "load_time_boxplot": { "boxplot": { "field": "load_time.seconds" } } }, ) print(resp)
response = client.search( index: 'latency', body: { size: 0, runtime_mappings: { 'load_time.seconds' => { type: 'long', script: { source: "emit(doc['load_time'].value / params.timeUnit)", params: { "timeUnit": 1000 } } } }, aggregations: { load_time_boxplot: { boxplot: { field: 'load_time.seconds' } } } } ) puts response
const response = await client.search({ index: "latency", size: 0, runtime_mappings: { "load_time.seconds": { type: "long", script: { source: "emit(doc['load_time'].value / params.timeUnit)", params: { timeUnit: 1000, }, }, }, }, aggs: { load_time_boxplot: { boxplot: { field: "load_time.seconds", }, }, }, }); console.log(response);
GET latency/_search { "size": 0, "runtime_mappings": { "load_time.seconds": { "type": "long", "script": { "source": "emit(doc['load_time'].value / params.timeUnit)", "params": { "timeUnit": 1000 } } } }, "aggs": { "load_time_boxplot": { "boxplot": { "field": "load_time.seconds" } } } }
箱线图值通常是近似的
编辑boxplot
度量使用的算法称为 TDigest(由 Ted Dunning 在使用 T-Digests 计算精确分位数中介绍)。
与其他百分位数聚合一样,箱线图也是非确定性的。这意味着使用相同的数据可能会得到略微不同的结果。
压缩
编辑近似算法必须在内存利用率和估计精度之间取得平衡。可以使用 compression
参数控制这种平衡。
resp = client.search( index="latency", size=0, aggs={ "load_time_boxplot": { "boxplot": { "field": "load_time", "compression": 200 } } }, ) print(resp)
response = client.search( index: 'latency', body: { size: 0, aggregations: { load_time_boxplot: { boxplot: { field: 'load_time', compression: 200 } } } } ) puts response
const response = await client.search({ index: "latency", size: 0, aggs: { load_time_boxplot: { boxplot: { field: "load_time", compression: 200, }, }, }, }); console.log(response);
GET latency/_search { "size": 0, "aggs": { "load_time_boxplot": { "boxplot": { "field": "load_time", "compression": 200 } } } }
TDigest 算法使用许多“节点”来近似分位数——可用的节点越多,精度越高(内存占用也越大),与数据量成正比。compression
参数将节点的最大数量限制为 20 * compression
。
因此,通过增加压缩值,您可以提高分位数的精度,但代价是需要更多内存。较大的压缩值还会使算法变慢,因为底层树状数据结构的大小会增加,从而导致更昂贵的操作。默认压缩值为 100
。
一个“节点”大约使用 32 字节的内存,因此在最坏的情况下(大量按顺序排序的数据),默认设置将产生一个大约 64KB 大小的 TDigest。实际上,数据往往更加随机,TDigest 将使用更少的内存。
执行提示
编辑TDigest 的默认实现针对性能进行了优化,可以扩展到数百万甚至数十亿个样本值,同时保持可接受的精度水平(在某些情况下,数百万个样本的相对误差接近 1%)。可以通过将参数 execution_hint
设置为值 high_accuracy
来使用针对精度优化的实现。
resp = client.search( index="latency", size=0, aggs={ "load_time_boxplot": { "boxplot": { "field": "load_time", "execution_hint": "high_accuracy" } } }, ) print(resp)
response = client.search( index: 'latency', body: { size: 0, aggregations: { load_time_boxplot: { boxplot: { field: 'load_time', execution_hint: 'high_accuracy' } } } } ) puts response
const response = await client.search({ index: "latency", size: 0, aggs: { load_time_boxplot: { boxplot: { field: "load_time", execution_hint: "high_accuracy", }, }, }, }); console.log(response);
GET latency/_search { "size": 0, "aggs": { "load_time_boxplot": { "boxplot": { "field": "load_time", "execution_hint": "high_accuracy" } } } }
此选项可以提高精度(在某些情况下,数百万个样本的相对误差接近 0.01%),但分位数查询的完成时间将延长 2 倍到 10 倍。
缺失值
编辑missing
参数定义如何处理缺少值的文档。默认情况下,它们将被忽略,但也可以将它们视为具有值。
resp = client.search( index="latency", size=0, aggs={ "grade_boxplot": { "boxplot": { "field": "grade", "missing": 10 } } }, ) print(resp)
response = client.search( index: 'latency', body: { size: 0, aggregations: { grade_boxplot: { boxplot: { field: 'grade', missing: 10 } } } } ) puts response
const response = await client.search({ index: "latency", size: 0, aggs: { grade_boxplot: { boxplot: { field: "grade", missing: 10, }, }, }, }); console.log(response);