## 操作符
---
### 二元操作符
Prometheus的查詢語言支持基本的邏輯運算和算術運算。對于兩個瞬時向量, [匹配行為](https://prometheus.io/docs/querying/operators/#vector-matching)可以被改變。
#### 算術二元運算符
在Prometheus系統中支持下面的二元算術操作符:
- `+` 加法
- `-` 減法
- `*` 乘法
- `/` 除法
- `%` 模
- `^` 冪等
二元運算操作符支持`scalar/scalar(標量/標量)`、`vector/scalar(向量/標量)`、和`vector/vector(向量/向量)`之間的操作。
在兩個標量之間進行操作符運算,得到的結果也是標量
在向量和標量之間,這個操作符會作用于這個向量的每個樣本值上。例如:如果一個時間序列瞬時向量除以2,操作結果也是一個新的瞬時向量,且度量指標名稱不變, 它是原度量指標瞬時向量的每個樣本值除以2.
在兩個向量之間,一個二元算術操作符作用在左邊瞬時向量的每個樣本值,且該樣本值與操作符右邊能匹配上的樣本值計算,[向量匹配](https://prometheus.io/docs/querying/operators/#vector-matching)。結果寫入到一個沒有度量指標名稱的瞬時向量。
#### 比較二元操作符
在Prometheus系統中,比較二元操作符有:
- `==` 等于
- `!=` 不等于
- `>` 大于
- `<` 小于
- `>=` 大于等于
- `<=` 小于等于
比較二元操作符被應用于`scalar/scalar(標量/標量)`、`vector/scalar(向量/標量)`,和`vector/vector(向量/向量)`。比較操作符得到的結果是`bool`布爾類型值,返回1或者0值。
在兩個標量之間的比較運算,bool結果寫入到另一個結果標量中。
瞬時向量和標量之間的比較運算,這個操作符會應用到某個當前時刻的每個時間序列數據上,如果一個時間序列數據值與這個標量比較結果是`false`,則這個時間序列數據被丟棄掉,如果是`true`, 則這個時間序列數據被保留在結果中。
在兩個瞬時向量之間的比較運算,左邊度量指標數據中的每個時間序列數據,與右邊度量指標中的每個時間序列數據匹配,沒有匹配上的,或者計算結果為false的,都被丟棄,不在結果中顯示。否則將保留左邊的度量指標和標簽的樣本數據寫入瞬時向量。
#### 邏輯/集合二元操作符
邏輯/集合二元操作符只能作用在即時向量, 包括:
- `and` 交集
- `or` 并集
- `unless` 補集
`vector1 and vector2` 的邏輯/集合二元操作符,規則:`vector1`瞬時向量中的每個樣本數據與`vector2`向量中的所有樣本數據進行標簽匹配,不匹配的,全部丟棄。運算結果是保留左邊的度量指標名稱和值。
`vector1 or vector2`的邏輯/集合二元操作符,規則: 保留`vector1`向量中的每一個元素,對于`vector2`向量元素,則不匹配`vector1`向量的任何元素,則追加到結果元素中。
`vector1 unless vector2`的邏輯/集合二元操作符,又稱差積。規則:包含在`vector1`中的元素,但是該元素不在`vector2`向量所有元素列表中,則寫入到結果集中。
### 向量匹配
向量之間的匹配是指右邊向量中的每一個元素,在左邊向量中也存在。這里有兩種基本匹配行為特征:
- 一對一,找到這個操作符的兩邊向量元素的相同元素。默認情況下,操作符的格式是`vector1 [operate] vector2`。如果它們有相同的標簽和值,則表示相匹配。`ingoring`關鍵字是指,向量匹配時,可以忽略指定標簽。`on`關鍵字是指,在指定標簽上進行匹配。格式如下所示:
> [vector expr] [bin-op] ignoring([label list]) [vector expr]
> [vector expr] [bin-op] on([lable 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="404"} 21
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="delete"} 34
method:http_requests:rate5m{method="post"} 120
```
查詢例子:
> method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
兩個向量之間的除法操作運算的向量結果是,每一個向量樣本http請求方法標簽值是500,且在過去5分鐘的運算值。如果沒有忽略`code="500"`的標簽,這里不能匹配到向量樣本數據。兩個向量的請求方法是`put`和`delete`的樣本數據不會出現在結果列表中
> {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\>
這個group帶標簽的修飾符標簽列表包含了“一對多”中的“一”一側的額外標簽。對于`on`標簽只能是這些列表中的一個。結果向量中的每一個時間序列數據都是唯一的。
`group`修飾符只能被用在比較操作符和算術運算符。
查詢例子:
> method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
在這個例子中,左向量的標簽數量多于左邊向量的標簽數量,所以我們使用`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 /600
> {method="post", code="404"} 0.175 // 21 /600
多對一和一對多匹配應該更多地被謹慎使用。經常使用`ignoring(\<labels\>)`輸出想要的結果。
### 聚合操作符
Prometheus支持下面的內置聚合操作符。這些聚合操作符被用于聚合單個即時向量的所有時間序列列表,把聚合的結果值存入到新的向量中。
- `sum` (在維度上求和)
- `max` (在維度上求最大值)
- `min` (在維度上求最小值)
- `avg` (在維度上求平均值)
- `stddev` (求標準差)
- `stdvar` (求方差)
- `count` (統計向量元素的個數)
- `count_values` (統計相同數據值的元素數量)
- `bottomk` (樣本值第k個最小值)
- `topk` (樣本值第k個最大值)
- `quantile` (統計分位數)
這些操作符被用于聚合所有標簽維度,或者通過`without`或者`by`子句來保留不同的維度。
> \<aggr-op\>([parameter,] \<vector expr\>) [without | by (\<label list\>)] [keep_common]
`parameter`只能用于`count_values`, `quantile`, `topk`和`bottomk`。`without`移除結果向量中的標簽集合,其他標簽被保留輸出。`by`關鍵字的作用正好相反,即使它們的標簽值在向量的所有元素之間。`keep_common`子句允許保留額外的標簽(在元素之間相同,但不在by子句中的標簽)
`count_values`對每個唯一的樣本值輸出一個時間序列。每個時間序列都附加一個標簽。這個標簽的名字有聚合參數指定,同時這個標簽值是唯一的樣本值。每一個時間序列值是結果樣本值出現的次數。
`topk`和`bottomk`與其他輸入樣本子集聚合不同,返回的結果中包括原始標簽。`by`和`without`僅僅用在輸入向量的桶中
例如:
如果度量指標名稱`http_requests_total`包含由`group`, `application`, `instance`的標簽組成的時間序列數據,我們可以通過以下方式計算去除`instance`標簽的http請求總數:
> sum(http_requests_total) without (instance)
如果我們對所有應用程序的http請求總數,我們可以簡單地寫下:
> sum(http_requests_total)
統計每個編譯版本的二進制文件數量,我們可以如下寫:
> count_values("version", build_version)
通過所有實例,獲取http請求第5個最大值,我們可以簡單地寫下:
> topk(5, http_requests_total)
### 二元運算符優先級
在Prometheus系統中,二元運算符優先級從高到低:
1. ^
2. *, /, %
3. +, -
4. ==, !=, <=, <, >=, >
5. and, unless
6. or