Percentiles Aggregation
這是一種多值指標聚合,用於計算聚合文檔提取數值的1個或多個百分位統計數據.
這些值既可通過文檔的特定字段提取,也可通過腳本來生成.
Percentiles通常用於查找異常值.
在正態分佈中,0.13%和99.87%表示與平均值的三個標準差。
任何超出三個標準差的數據通常被視為異常。
當檢索到一系列百分位數時,可使用它們來評估數據的分佈情況,並確定數據是否存在偏斜/雙峰等。
假設你的數據由網頁加載時間所構成. 平均和中值加載時間對管理員來說,並無多大用處. 最大值可能很有用,但它會被慢響應所扭曲.
下面讓我們查一下加載時間的百分位數範圍:
GET latency/data/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"field" : "load_time" #1
}
}
}
}
1 load_time字段必須是數值字段
默認情況下, percentile指標會生成一組百分位: [ 1, 5, 25, 50, 75, 95, 99 ].
其響應類似於:
{
...
"aggregations": {
"load_time_outlier": {
"values" : {
"1.0": 9.9,
"5.0": 29.500000000000004,
"25.0": 167.5,
"50.0": 445.0,
"75.0": 722.5,
"95.0": 940.5,
"99.0": 980.1000000000001
}
}
}
}
正如上面所展示的,聚合返回默認範圍內每個百分位的統計值。如果我們假設響應時間的單位是毫秒,那麼很明顯網頁一般都會在10-723毫秒內加載完畢,但偶爾加載時間到達到941-980毫秒。
通過,管理員只對極端數值感興趣.因此,可以在請求中指定我們感興趣的百分位(請求百分位必須在 0-100之間):
GET latency/data/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"field" : "load_time",
"percents" : [95, 99, 99.9] #1
}
}
}
}
1.使用percents參數來指定要計算的百分位
Keyed Response(分組響應/按鍵響應)
默認keyed為true,該標誌會將不同字符串鍵與每個桶進行關聯,並以hash形式(非數組)來返回百分位結果. 將keyed設為false,可禁用這種行為:
GET latency/data/_search
{
"size": 0,
"aggs": {
"load_time_outlier": {
"percentiles": {
"field": "load_time",
"keyed": false
}
}
}
}
響應:
{
...
"aggregations": {
"load_time_outlier": {
"values": [
{
"key": 1.0,
"value": 9.9
},
{
"key": 5.0,
"value": 29.500000000000004
},
{
"key": 25.0,
"value": 167.5
},
{
"key": 50.0,
"value": 445.0
},
{
"key": 75.0,
"value": 722.5
},
{
"key": 95.0,
"value": 940.5
},
{
"key": 99.0,
"value": 980.1000000000001
}
]
}
}
}
Script
百分位指標聚合也支持腳本。例如,如果加載時間單位是毫秒,但我們想以秒來計算百分位計算,則可使用腳本來修改:
GET latency/data/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"script" : {
"lang": "painless",
"source": "doc['load_time'].value / params.timeUnit", #1
"params" : {
"timeUnit" : 1000 #2
}
}
}
}
}
}
1 field參數已被script參數所替換,即使用腳本來計算百分位數值
2 與其它腳本一樣,它也支持參數化輸入
這會使用painless腳本語言來將script參數解析為內聯腳本(不帶腳本參數)。
可通過如下語法來使用存儲腳本:
GET latency/data/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"script" : {
"id": "my_script",
"params": {
"field": "load_time"
}
}
}
}
}
}
百分位數是近似值
有多種算法可計算百分位數值. 簡單的實現方式是將所有值存儲在排序數組中。
在查找50th百分位數值,你只需要查找my_array[count(my_array) * 0.5]中的最後一個值.
很顯然,上述簡單實現不具備擴展性—排序數組會隨著數據集數量線性增長。
要計算Elasticsearch集群中潛在數十億個值的百分位數,只能計算其近似百分位數。
百分位指標使用的算法稱為TDigest (可參考Ted Dunning的Computing Accurate Quantiles using T-Digests).
使用此指標時,須注意以下幾條規則:
- 精度與q(1-q)成正比.也就是說,極端百分位數(例如99%)比不太極端的百分位數(例如中位數)更準確.
- 對於較小的值集,百分位數非常準確(如果數據足夠小,則可能100%準確)。
- 隨著桶內數據增加,算法的準確性會下降(近似百分位數)。 它有效地節省了內存的交易準確性。準確性到底是多少,這很難評估,因為它取決於數據分佈和聚合的數據量。
下圖顯示了均勻分佈的相對誤差,具體取決於所收集的數據數量和請求的百分位數:
它顯示了極端百分位數的精度更好。 大量值誤差較小的原因在於,大數定律使得值的分佈越來越均勻,並且t-digest樹在總結它時可以做得更好。 對於更偏斜的分佈,情況就不是這樣了。
壓縮
近似算法必須平衡內存利用率和估算的準確性。 可以使用compression參數來控制此平衡:
GET latency/data/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"field" : "load_time",
"tdigest": {
"compression" : 200 #1
}
}
}
}
}
1 控制內存使用和近似錯誤
TDigest算法會使用許多“節點”來估算百分位數 - 可用節點越多,與數據量成正比的準確度(以及內存佔用量)就越高。compression參數將最大節點數限制為20 * compression。
因此,通過增加壓縮值,則可以犧牲更多的內存來提高百分位數的準確性。
但,過大的壓縮值會使算法變慢,因為底層樹數據結構的大小會增加,從而導致更昂貴的操作。
默認壓縮值為100。每個“節點”使用大約32個字節的內存,因此在最壞情況下,默認設置將產生大約64KB的TDigest。 在實踐中,數據分佈往往更隨機,因此TDigest消耗的內存會少些。
HDR Histogram
注意
此設置公開了HDR直方圖的內部實現,其語法可能會在將來發生變化。
HDR Histogram (High Dynamic Range Histogram) 是另一種替代實現,在計算延遲測量的百分位數時非常有用,因為它的實現比t-digest更快,但同時消耗的內存也更大。此實現能保持固定的最壞情況百分比錯誤(指定為有效位數)。也就是說,如果在直方圖中以1微秒到1小時(3600000000微秒)的值記錄數據,並將其設置為3個有效數字,則對於高達1毫秒的值,其值分辨率將保持為1微秒;對於最大跟蹤值(1小時),其值分辨率將保持為3.6秒(或更好)。
可在請求中指定方法參數來使用HDR Histogram:
GET latency/data/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"field" : "load_time",
"percents" : [95, 99, 99.9],
"hdr": { #1
"number_of_significant_value_digits" : 3 #2
}
}
}
}
}
1 hdr對象表示應使用HDR Histogram 來計算百分位數,並且可以在對象內指定此算法的特殊設置。
2 number_of_significant_value_digits可用來指定直方圖分辨率的有效位數。
HDR Histogram只支持正值,如果傳遞負值,則會出錯。 如果值的範圍未知,則最好不要使用HDR Histogram,因為這可能會導致非常高的內存消耗。
Missing value
missing 參數用於定義如何處理文檔中的缺失值。
默認,它會忽略缺失值,但也可以將其視為有值字段。
GET latency/data/_search
{
"size": 0,
"aggs" : {
"grade_percentiles" : {
"percentiles" : {
"field" : "grade",
"missing": 10 #1
}
}
}
}
1 對於無值的grade字段,其所屬文檔會與值為0的文檔放在同一個桶內。
全部指標聚合,請參考
單值指標聚合
多值指標聚合
地理位置相關聚合
可執行Map-Reduce計算的聚合
閱讀更多 Java源 的文章