運算子
PromQL 支援一元、二元和聚合運算子。
一元運算子
PromQL 中唯一的一元運算子是 -(一元負號)。它可以應用於標量或瞬時向量。在前一種情況下,它返回一個符號相反的標量。在後一種情況下,它返回一個瞬時向量,其中每個元素的符號都相反。透過將所有桶(bucket)中的樣本數、觀測總數(count)和觀測總和(sum)的符號取反,來對直方圖樣本進行取反。得到的直方圖樣本總是被視為儀表型直方圖(gauge histogram)。
注意具有任何負桶樣本數或負觀測總數的直方圖只能用作中間結果。如果這種負直方圖是記錄規則的最終輸出,規則評估將會失敗。負直方圖無法透過任何交換格式(exposition、remote-write、OTLP)來表示,因此無法以任何方式攝入到 Prometheus 中,它們只能透過 PromQL 表示式建立。
二元運算子
二元運算子涵蓋了基本的邏輯和算術運算。對於兩個瞬時向量之間的運算,可以修改其匹配行為。
算術二元運算子
PromQL 中存在以下二元算術運算子
+(加法)-(減法)*(乘法)/(除法)%(取模)^(冪/指數)
二元算術運算子定義在標量/標量、向量/標量和向量/向量值對之間。它們遵循通常的 IEEE 754 浮點運算規範 ,包括對特殊值如 NaN、+Inf 和 -Inf 的處理。
在兩個標量之間,其行為非常直觀:它們求值為另一個標量,該標量是將運算子應用於兩個標量運算元的結果。
在瞬時向量和標量之間,運算子將應用於向量中每個資料樣本的值。
如果資料樣本是浮點數(float),則在該浮點數與標量之間執行運算。例如,如果將包含浮點樣本的瞬時向量乘以 2,則結果是另一個浮點樣本向量,其中原始向量的每個樣本值都乘以 2。
對於作為直方圖樣本的向量元素,其行為如下
-
對於
*,所有桶中的樣本數、觀測總數和觀測總和都乘以該標量。如果標量為負,則生成的直方圖被視為儀表型直方圖。否則,保留輸入直方圖樣本的計數器(counter)型或儀表(gauge)型屬性。 -
對於
/,直方圖樣本必須在左側(LHS),右側(RHS)為標量。然後將所有桶中的樣本數、觀測總數和觀測總和除以該標量。除以零將導致產生一個沒有常規桶的直方圖,且零桶樣本數、觀測總數和總和分別被設定為+Inf、-Inf或NaN,具體取決於它們在輸入直方圖中的值(分別為正、負或零/NaN)。如果標量為負,則生成的直方圖被視為儀表型直方圖。否則,保留輸入直方圖樣本的計數器型或儀表型屬性。 -
對於左側為標量、右側為直方圖樣本的
/,以及標量和直方圖樣本任意組合的所有其他算術二元運算子,運算均無結果,並且相應的元素會從結果向量中移除。此類移除會透過資訊級(info-level)批註進行標記。
在兩個瞬時向量之間,二元算術運算子應用於左側向量中的每個條目與其在右側向量中的匹配元素。結果傳播到結果向量中,分組標籤成為輸出標籤集。預設情況下,如果在另一個向量中找不到匹配條目,則該時間序列不包含在結果中。可以使用填充修飾符來調整此行為。
如果兩個浮點樣本相匹配,則將算術運算子應用於這兩個輸入值。
如果浮點樣本與直方圖樣本匹配,則其行為遵循與標量和直方圖樣本之間相同的邏輯(見上文),即 * 和 /(後者直方圖樣本在左側)是有效操作,而所有其他操作都會導致從結果向量中移除相應的元素。
如果兩個直方圖樣本匹配,則只有 + 和 - 是有效操作,分別對所有匹配的桶中樣本數、觀測總數和總和進行加減。所有其他操作都會導致從輸出向量中移除相應的元素,並由資訊級批註進行標記。+ 和 - 操作通常只應應用於儀表型直方圖,但 PromQL 也允許將其用於計數器型直方圖,以覆蓋特定的用例。對於這些用例,需要特別注意避免由於計數器重置未對齊而導致的問題。(PromQL 可以檢測到某些計數器重置的不相容性,並使用警告級批註進行標記。)將兩個計數器型直方圖相加會得到一個計數器型直方圖。運算元的所有其他組合以及所有減法都會得到儀表型直方圖。
在任何涉及向量的二元算術運算中,指標名稱都會被丟棄。即使在 on 中顯式提及了 __name__,也會發生這種情況(有關進一步探討,請參閱 https://github.com/prometheus/prometheus/issues/16631 )。
對於任何可能導致負直方圖的算術二元運算,請參閱上文中的相應說明。
三角二元運算子
Prometheus 中存在以下以弧度為單位工作的三角二元運算子
atan2(基於 https://pkg.go.dev/math#Atan2 )
三角運算子允許透過向量匹配在兩個向量上執行三角函式,這在普通函式中是無法實現的。它們的行為方式與算術運算子相同。它們僅對浮點樣本起作用。涉及直方圖樣本的操作會導致從輸出向量中移除相應的向量元素,並由資訊級批註進行標記。
直方圖裁剪運算子
Prometheus 中存在以下二元直方圖裁剪運算子
</(上限裁剪):移除高於閾值的所有觀測值>/(下限裁剪):移除低於閾值的所有觀測值
直方圖裁剪運算子定義在向量/標量和向量/向量值對之間,其中左側是原生直方圖(指數型或 NHCB),右側是浮點閾值。
如果閾值沒有與直方圖的某個桶邊界對齊,則會採用線性插值(針對 NHCB 和指數直方圖的零桶)或指數插值(針對指數直方圖的非零桶)來計算包含閾值的桶中剩餘的估算觀測數。
當某些觀測值被裁剪時,會根據剩餘的觀測值重新(近似地)計算新的觀測值總和。
比較二元運算子
Prometheus 中存在以下二元比較運算子
==(等於)!=(不等於)>(大於)<(小於)>=(大於等於)<=(小於等於)
比較運算子定義在標量/標量、向量/標量和向量/向量值對之間。預設情況下它們充當過濾器。可以透過在運算子後提供 bool 來修改它們的行為,這將返回 0 或 1 作為值,而不是進行過濾。
在兩個標量之間,必須提供 bool 修飾符,這些運算子將產生另一個標量,該標量為 0(false)或 1(true),具體取決於比較結果。
在瞬時向量和標量之間,這些運算子將應用於向量中每個資料樣本的值,比較結果為假的向量元素會從結果向量中被丟棄。這些運算僅適用於向量中的浮點樣本。對於直方圖樣本,相應的元素會被從結果向量中移除,並由資訊級批註進行標記。
在兩個瞬時向量之間,這些運算子預設表現為過濾器,應用於匹配的條目。表示式不為真或在表示式另一側找不到匹配項的向量元素會從結果中被丟棄,而其他元素則會傳播到結果向量中,分組標籤成為輸出標籤集。
兩個浮點樣本之間的匹配照常進行。
浮點樣本與直方圖樣本之間的匹配是無效的,相應的元素會從結果向量中被移除,並由資訊級批註進行標記。
在兩個直方圖樣本之間,== 和 != 的工作方式與預期一致,但所有其他比較二元運算依然無效。
在任何涉及向量的比較二元運算中,提供 bool 修飾符會按以下方式改變行為
- 在表示式另一側找到匹配項但表示式為假的向量元素的值將變為
0,而找到匹配項且表示式為真的向量元素的值將變為1。(請注意,沒有匹配項的元素或涉及直方圖樣本的無效操作仍將不返回任何結果,而不是返回0。) - 指標名稱會被丟棄。
如果不提供 bool 修飾符,則保留左側的指標名稱,但有以下例外情況
- 如果使用了
on,則丟棄指標名稱。 - 如果使用了
group_right,則保留右側的指標名稱,以避免衝突。
邏輯/集合二元運算子
這些邏輯/集合二元運算子僅定義在瞬時向量之間
and(交集)or(並集)unless(補集)
vector1 and vector2 的結果是一個向量,該向量由 vector1 中那些在 vector2 中擁有完全匹配標籤集的元素組成。其他元素將被丟棄。指標名稱和值從左側向量中繼承。
vector1 or vector2 的結果是一個向量,其中包含 vector1 的所有原始元素(標籤集 + 值),以及 vector2 中在 vector1 中沒有匹配標籤集的所有元素。
vector1 unless vector2 的結果是一個向量,該向量由 vector1 中那些在 vector2 中沒有完全匹配標籤集的元素組成。兩個向量中所有相匹配的元素都會被丟棄。
由於這些邏輯/集合二元運算子不與樣本值進行互動,因此它們在浮點樣本和直方圖樣本上的工作方式相同。
向量匹配
向量之間的運算會嘗試在右側向量中為左側的每個條目尋找一個匹配的元素。匹配行為有兩種基本型別:一對一和多對一/一對多。
向量匹配關鍵字
這些向量匹配關鍵字允許在具有不同標籤集的時間序列之間進行匹配
on(<標籤列表>):僅在提供的標籤上進行匹配。ignoring(<標籤列表>):匹配時忽略提供的標籤。
提供給匹配關鍵字的標籤列表將決定向量如何組合。示例可以在一對一向量匹配和多對一和一對多向量匹配中找到。
分組修飾符
這些分組修飾符啟用了多對一/一對多向量匹配
group_left:允許多對一匹配,其中左側向量具有更高的基數(cardinality)。group_right:允許一對多匹配,其中右側向量具有更高的基數。
可以向分組修飾符提供包含“一”側標籤的標籤列表,以便將其包含在結果指標中。
多對一和一對多匹配是高階用例,應當謹慎考慮。通常,合理使用 ignoring(<標籤>) 就能提供所需的結果。
分組修飾符僅能用於比較、算術和三角運算子。集合運算子預設會與兩側所有可能的條目進行匹配。
一對一向量匹配
一對一從操作的每一側尋找唯一的一對條目。在預設情況下,這是遵循 vector1 <運算子> vector2 格式的操作。如果兩個條目具有完全相同的標籤集和對應值,則它們匹配。ignoring 關鍵字允許在匹配時忽略某些標籤,而 on 關鍵字允許將考慮的標籤集縮小到提供的列表中。
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
示例輸入
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
示例查詢
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
這將返回一個結果向量,其中包含過去 5 分鐘內每個方法的 HTTP 請求中狀態碼為 500 的佔比。如果沒有 ignoring(code),由於指標沒有共享相同的標籤集,將不會有任何匹配。方法為 put 和 del 的條目沒有匹配項,將不會顯示在結果中。
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
多對一和一對多向量匹配
多對一和一對多匹配是指“一”側的每個向量元素可以與“多”側的多個元素相匹配的情況。這必須使用 group_left 或 group_right 修飾符來顯式請求,其中左/右決定了哪個向量具有更高的基數。
<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>
隨分組修飾符提供的標籤列表包含來自“一”側的附加標籤,以便包含在結果指標中。對於 on,一個標籤只能出現在其中一個列表中。結果向量的每個時間序列必須是唯一可識別的。
示例查詢
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
在這種情況下,左側向量中每個 method 標籤值包含多個條目。因此,我們使用 group_left 來指示這一點。右側的元素現在與左側具有相同 method 標籤的多個元素進行匹配。
{method="get", code="500"} 0.04 // 24 / 600
{method="get", code="404"} 0.05 // 30 / 600
{method="post", code="500"} 0.05 // 6 / 120
{method="post", code="404"} 0.175 // 21 / 120
填充缺失的匹配項
填充修飾符處於實驗性階段,必須透過 --enable-feature=promql-binop-fill-modifiers 啟用。
預設情況下,在二元運算的另一側找不到匹配項的向量元素不會包含在結果向量中。填充修飾符允許透過使用提供的預設樣本值在二元運算的任意一側填充缺失的序列來覆蓋此行為。
fill(<值>):使用值填充任意一側缺失的匹配項。fill_left(<值>):使用值填充左側缺失的匹配項。fill_right(<值>):使用值填充右側缺失的匹配項。
值 必須是表示浮點樣本的數值字面量。不支援直方圖樣本。
請注意,這些修飾符只能填充在操作的其中一側缺失的序列。如果一個序列在兩側都缺失,則無法透過這些修飾符建立。
填充修飾符可以用於以下組合
fill(<預設值>)fill_left(<預設值>)fill_right(<預設值>)fill_left(<預設值>) fill_right(<預設值>)fill_right(<預設值>) fill_left(<預設值>)
如果使用了諸如 bool、on、ignoring、group_left 或 group_right 等其他二元運算子修飾符,則必須將填充修飾符放在最後。
當與 group_left 或 group_right 結合使用填充修飾符時,它們的行為如下
- 如果填充修飾符用於匹配的“多”側,它將僅為每個匹配組的“多”側填充一個單獨的序列,並使用該組的匹配標籤作為序列標識。
- 如果填充修飾符用於匹配的“一”側,並且分組修飾符指定了要從“一”側包含的標籤名稱(例如
left_vector * on(instance, job) group_left(info_label) fill_right(1) right_vector),則這些標籤不會為缺失的序列進行填充,因為沒有它們的數值來源。
集合運算子(and、or、unless)不支援填充修飾符,因為這些運算子的目的就是基於在另一個向量中的存在與否來過濾序列。
示例查詢,用 0 填充任意一側缺失的序列
method_code:http_errors:rate5m{status="500"} / ignoring(code) fill(0) method:http_requests:rate5m
這將返回一個結果向量,其中包含過去 5 分鐘內每個方法的 HTTP 請求中狀態碼為 500 的佔比。方法為 put 和 del 的條目現在包含在結果中,並填充了預設樣本值 0,因為它們在各自的另一側沒有匹配的序列。
{method="get"} 0.04 # 24 / 600
{method="put"} +Inf # 3 / 0 (missing right side filled in)
{method="del"} 0 # 0 / 34 (missing left side filled in)
{method="post"} 0.05 # 6 / 120
聚合運算子
Prometheus 支援以下內建聚合運算子,可用於聚合單個瞬時向量的元素,從而產生一個元素更少且帶有聚合值的新向量
-
sum(v)(計算維度上的總和) -
avg(v)(計算維度上的算術平均值) -
min(v)(選擇維度上的最小值) -
max(v)(選擇維度上的最大值) -
bottomk(k, v)(按樣本值最小的k個元素) -
topk(k, v)(按樣本值最大的k個元素) -
limitk(k, v)(取樣k個元素,實驗性,必須透過--enable-feature=promql-experimental-functions啟用) -
limit_ratio(r, v)(取樣偽隨機比例為r的元素,實驗性,必須透過--enable-feature=promql-experimental-functions啟用) -
group(v)(結果向量中的所有值都為 1) -
count(v)(計算向量中的元素個數) -
count_values(l, v)(計算具有相同值的元素個數) -
stddev(v)(計算維度上的總體標準差) -
stdvar(v)(計算維度上的總體方差) -
quantile(φ, v)(計算維度上的 φ-分位數 (0 ≤ φ ≤ 1))
這些運算子既可用於對所有標籤維度進行聚合,也可透過引入 without 或 by 子句來保留特定的維度。這些子句可以在表示式之前或之後使用。
<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)
或
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
標籤列表 是未加引號的標籤列表,其中可以包含尾隨逗號,即 (label1, label2) 和 (label1, label2,) 都是有效的語法。
without 會從結果向量中移除列出的標籤,而保留輸出中的所有其他標籤。by 的作用相反,它會丟棄未在 by 子句中列出的標籤,即使這些標籤在向量的所有元素中的值是完全相同的。
詳細說明
sum
sum(v) 對 v 中的樣本值求和,其方式與 + 二元運算子在兩個值之間求和的方式相同。
聚合到單個結果向量元素中的所有樣本值必須全為浮點樣本,或全為直方圖樣本。混合兩者的聚合是無效的,會導致從輸出向量中移除相應的向量元素,並由警告級(warn-level)批註進行標記。
示例
如果指標 memory_consumption_bytes 的時間序列根據 application、instance 和 group 標籤進行展開,我們可以透過以下方式計算每個應用和分組在所有例項上的總記憶體消耗:
sum without (instance) (memory_consumption_bytes)
這等價於
sum by (application, group) (memory_consumption_bytes)
如果我們只對所有應用的總記憶體消耗感興趣,我們只需寫成:
sum(memory_consumption_bytes)
avg
avg(v) 將 v 的總和除以聚合樣本的數量,其方式與 / 二元運算子相同。
聚合到單個結果向量元素中的所有樣本值必須全為浮點樣本,或全為直方圖樣本。混合兩者的聚合是無效的,會導致從輸出向量中移除相應的向量元素,並由警告級(warn-level)批註進行標記。
min 和 max
min(v) 和 max(v) 分別返回 v 中的最小值或最大值。
它們僅適用於浮點樣本,並遵循 IEEE 754 浮點運算規範。這尤其意味著,只有當所有聚合值均為 NaN 時,NaN 才會作為最小值或最大值。輸入向量中的直方圖樣本會被忽略,並由資訊級批註進行標記。
topk 和 bottomk
topk(k, v) 和 bottomk(k, v) 與其他聚合器的不同之處在於,結果向量中會返回輸入樣本中 k 個值的子集,其中包括原始標籤。
by 和 without 僅用於對輸入向量進行分桶。
與 min 和 max 類似,它們僅適用於浮點樣本,並分別將 NaN 值視為最遠離頂部或底部。輸入向量中的直方圖樣本會被忽略,並由資訊級批註進行標記。
如果用於瞬時查詢,topk 和 bottomk 會分別返回按值降序或升序排列的序列。如果與 by 或 without 結合使用,則每個桶內的序列將按值排序,並且同一個桶中的序列會連續返回,但無法保證序列桶會按任何特定順序返回。
排序不適用於範圍查詢。
示例
要獲取所有例項中記憶體消耗最高的 5 個例項,我們可以寫成:
topk(5, memory_consumption_bytes)
limitk
limitk(k, v) 返回 k 個輸入樣本的子集,結果向量中包括原始標籤。
該子集以確定性的偽隨機方式選擇。這與樣本型別無關。因此,它同時適用於浮點樣本和直方圖樣本。
示例
要取樣 10 個時間序列,我們可以寫成:
limitk(10, memory_consumption_bytes)
limit_ratio
limit_ratio(r, v) 返回輸入樣本的一個子集,結果向量中包括原始標籤。
該子集以確定性的偽隨機方式選擇。這與樣本型別無關。因此,它同時適用於浮點樣本和直方圖樣本。
r 的值可以介於 +1 和 -1 之間。r 的絕對值用作選擇比例,但對於負的 r,選擇順序會反轉,這可用於選擇補集。例如,limit_ratio(0.1, ...) 返回大約 10% 的確定性輸入樣本集,而 limit_ratio(-0.9, ...) 則精確返回未被 limit_ratio(0.1, ...) 返回的剩餘約 90% 的輸入樣本。
group
group(v) 為在特定時間戳包含任何值的每個分組返回 1。
該值可以是浮點或直方圖樣本。
count
count(v) 返回該時間戳的值的數量,如果在該時間戳沒有值,則不返回任何值。
該值可以是浮點或直方圖樣本。
count_values
count_values(l, v) 為 v 中的每個唯一樣本值輸出一個時間序列。每個序列都有一個由 l 指定的附加標籤,其標籤值為該唯一的樣本值。每個時間序列的值是該樣本值出現的次數。
count_values 同時適用於浮點樣本和直方圖樣本。對於後者,直方圖樣本值的緊湊字串表示形式將用作標籤值。
示例
要計算執行每個構建版本的二進位制檔案數量,我們可以寫成:
count_values("version", build_version)
stddev
stddev(v) 返回 v 的標準差。
stddev 僅適用於浮點樣本,遵循 IEEE 754 浮點運算規範。輸入向量中的直方圖樣本會被忽略,並由資訊級批註進行標記。
stdvar
stdvar(v) 返回 v 的方差。
stdvar 僅適用於浮點樣本,遵循 IEEE 754 浮點運算規範。輸入向量中的直方圖樣本會被忽略,並由資訊級批註進行標記。
quantile
quantile(φ, v) 計算 φ-分位數,即在所聚合維度的 N 個指標值中排名第 φ*N 的值。
quantile 僅適用於浮點樣本。輸入向量中的直方圖樣本會被忽略,並由資訊級批註進行標記。
NaN 被視為可能的最小值。
例如, quantile(0.5, ...) 計算中位數,quantile(0.95, ...) 計算第 95 百分位數。
特殊情況
- 當 φ =
NaN時,返回NaN。 - 當 φ < 0 時,返回
-Inf。 - 當 φ > 1 時,返回
+Inf。
二元運算子優先順序
下表按從高到低的順序列出了 Prometheus 中二元運算子的優先順序。
^*、/、%、atan2+,-==,!=,<=,<,>=,>and、unless或
處於相同優先順序水平的運算子是左結合的。例如,2 * 3 % 2 等價於 (2 * 3) % 2。然而,^ 是右結合的,因此 2 ^ 3 ^ 2 等價於 2 ^ (3 ^ 2)。