> For the complete documentation index, see [llms.txt](https://bohans.gitbook.io/devops/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bohans.gitbook.io/devops/prometheus/promql/promql-cao-zuo-fu.md).

# PromQL 操作符

使用 PromQL 除了能够方便的按照查询和过滤时间序列以外，PromQL 还支持丰富的操作符，用户可以使用这些操作符进一步的对事件序列进行二次加工。

这些操作符包括：**数学运算符**，**逻辑运算符**，**布尔运算符**等等。

## 数学运算符

{% hint style="info" %}

* **瞬时向量与标量之间进行数学运算**时，**数学运算符会依次作用于瞬时向量中的每一个样本值**，从而得到一组新的时间序列。
* **瞬时向量与瞬时向量之间进行数学运算**时，**数学运算符会**依次找到与左边向量元素匹配（标签完全一致）的右边向量元素进行运算，如果没找到匹配元素，则直接丢弃。
  {% endhint %}

PromQL 支持的所有数学运算符如下所示：

* `+` (加法)
* `-` (减法)
* `*` (乘法)
* `/` (除法)
* `%` (求余)
* `^` (幂运算)

## 布尔运算符

<mark style="color:blue;">**布尔运算支持用户根据时间序列中样本的值，对时间序列进行过滤。**</mark>

{% hint style="info" %}

* **瞬时向量与标量进行布尔运算**时，PromQL 依次比较向量中的所有时间序列样本的值，如果比较结果为 true 则保留，反之丢弃。
* **瞬时向量与瞬时向量直接进行布尔运算**时，同样遵循默认的匹配模式：依次找到与左边向量元素匹配（标签完全一致）的右边向量元素进行相应的操作，如果没找到匹配元素，则直接丢弃。
  {% endhint %}

PromQL  支持的布尔运算符如下：

* `==` (相等)
* `!=` (不相等)
* `>` (大于)
* `<` (小于)
* `>=` (大于等于)
* `<=` (小于等于)

### 使用 bool 修饰符改变布尔运算符的行为

**布尔运算符的默认行为是对时序数据进行过滤，**&#x53EF;以使用 bool 修饰符改变布尔运算的默认行为，从而得到真正的布尔结果。

例如：

```java
http_requests_total > bool 1000
```

<mark style="color:blue;">**使用 bool 修改符后，布尔运算不会对时间序列进行过滤，而是将瞬时向量中的各个样本数据与标量的比较结果转换为 0 或者 1，从而形成一条新的时间序列。**</mark>

{% code overflow="wrap" %}

```json
http_requests_total{code="200",handler="query",instance="localhost:9090",job="prometheus",method="get"}  1
http_requests_total{code="200",handler="query_range",instance="localhost:9090",job="prometheus",method="get"}  0
```

{% endcode %}

## 集合运算符

<mark style="color:blue;">**通过集合运算，可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。**</mark>

目前，Prometheus支持以下集合运算符：

* `and` (并且)
* `or` (或者)
* `unless` (排除)

## 匹配模式详解

**向量与向量之间进行运算操作时会基于默认的匹配规则**：<mark style="color:blue;">**依次找到与左边向量元素匹配（标签完全一致）的右边向量元素进行运算，如果没找到匹配元素，则直接丢弃。**</mark>

在 PromQL 中有两种典型的匹配模式：

* **一对一（one-to-one）**
* **多对一（many-to-one）**&#x6216;**一对多（one-to-many）**

### 一对一匹配

一对一匹配模式会对操作符两边的瞬时向量依次进行比较并找到唯一匹配（标签完全一致）的样本值。

默认情况下，表达式如下：

```markup
vector1 <operator> vector2
```

在操作符两边表达式标签不一致的情况下，可以使用 <mark style="color:blue;">**on(label list)**</mark> 或者 <mark style="color:blue;">**ignoring(label list)**</mark> 来修改便签的匹配行为。

* 使用 ignoreing 可以在匹配时忽略某些标签
* 使用 on 则可以将匹配行为限定在某些标签之内

```markup
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
```

<details>

<summary><mark style="color:purple;"><strong>示例</strong></mark></summary>

存在下列样本：

```json
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
```

使用 PromQL 表达式：

{% code overflow="wrap" %}

```java
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
```

{% endcode %}

该表达式会返回在过去 5 分钟内，HTTP 请求状态码为 500 的请求在所有请求中的比例。如果没有使用 ignoring(code)，操作符两边表达式返回的瞬时向量中将找不到任何一个标签完全相同的匹配项。

因此结果如下：

```json
{method="get"}  0.04            //  24 / 600
{method="post"} 0.05            //   6 / 120
```

</details>

### 多对一和一对多匹配

多对一和一对多两种匹配模式指的是 “一” 侧的每一个向量元素可以与 "多" 侧的多个元素匹配的情况。

在这种情况下，必须使用 **group 修饰符**：<mark style="color:blue;">**group\_left**</mark> 或者 <mark style="color:blue;">**group\_right**</mark> 来确定哪一个向量具有更高的基数（充当“多”的角色）。

```markup
<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>
```

<details>

<summary><mark style="color:purple;"><strong>示例</strong></mark></summary>

存在下列样本：

```json
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
```

使用表达式：

{% code overflow="wrap" %}

```java
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
```

{% endcode %}

在限定匹配标签后，右向量中的元素可能匹配到多个左向量中的元素。因此该表达式的匹配模式为多对一，需要使用 group 修饰符 group\_left 指定左向量具有更好的基数。

最终的运算结果如下：

```json
{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
```

</details>
