操作符

二元操作符

Prometheus 的查询语言支持基本的逻辑和算术操作符。对于两个瞬时向量之间的操作,可以修改其匹配行为

算术二元操作符

Prometheus 中存在以下二元算术操作符

  • + (加)
  • - (减)
  • * (乘)
  • / (除)
  • % (模)
  • ^ (幂)

二元算术操作符定义在标量/标量、向量/标量以及向量/向量值对之间。它们遵循通常的 IEEE 754 浮点算术,包括处理特殊值,例如 NaN+Inf-Inf

在两个标量之间,行为很明显:它们计算出另一个标量,该标量是将操作符应用于两个标量操作数的结果。

在瞬时向量和标量之间,操作符应用于向量中每个数据样本的值。如果数据样本是浮点数,对数据样本执行的操作也很明显,例如,如果一个浮点样本的瞬时向量乘以 2,结果是另一个浮点样本向量,其中原始向量的每个样本值都乘以 2。对于直方图样本的向量元素,行为如下:对于 *,所有桶(bucket)的计数、总数和观察值总和都乘以该标量。对于 /,直方图样本必须在左侧 (LHS),标量在右侧 (RHS)。然后,所有桶的计数、总数和观察值总和都除以该标量。除以零会导致一个没有常规桶的直方图,零桶的计数、总数和观察值总和都设置为 +Inf、-Inf 或 NaN,具体取决于它们在输入直方图中的值(分别为正、负或零/NaN)。对于左侧 (LHS) 是标量而右侧 (RHS) 是直方图样本的 / 操作,以及所有其他涉及标量和直方图样本组合的算术二元操作符,都没有结果,相应的元素将从结果向量中移除。此类移除会通过信息级别(info-level)注释标记。

在两个瞬时向量之间,算术二元操作符应用于左侧向量 (LHS) 中的每个条目及其在右侧向量 (RHS) 中的匹配元素。结果会被传递到结果向量中,分组标签成为输出标签集。在右侧向量中找不到匹配条目的条目不会成为结果的一部分。如果两个浮点样本匹配,行为很明显。如果一个浮点样本与一个直方图样本匹配,行为遵循与标量和直方图样本之间相同的逻辑(见上文),即 */(后者需要直方图样本在左侧 LHS)是有效操作,而所有其他操作都会导致相应的元素从结果向量中移除。此类移除会通过信息级别注释标记。如果两个直方图样本匹配,只有 +- 是有效操作,每个操作分别对所有匹配的桶计数、总数和观察值总和进行相加或相减。所有其他操作都会导致相应的元素从结果向量中移除,并由信息级别注释标记。

在任何涉及向量的算术二元操作中,指标名称都会被移除。

三角函数二元操作符

Prometheus 中存在以下以弧度为单位的三角函数二元操作符

三角函数操作符允许使用向量匹配对两个向量执行三角函数运算,这是普通函数无法做到的。它们的作用方式与算术操作符相同。它们只对浮点样本进行操作。涉及直方图样本的操作会导致相应的向量元素从输出向量中移除,并由信息级别注释标记。

比较二元操作符

Prometheus 中存在以下二元比较操作符

  • == (等于)
  • != (不等于)
  • > (大于)
  • < (小于)
  • >= (大于或等于)
  • <= (小于或等于)

比较操作符定义在标量/标量、向量/标量以及向量/向量值对之间。默认情况下,它们会进行过滤。通过在操作符后面提供 bool,可以修改它们的行为,此时将返回值 01 而不是进行过滤。

在两个标量之间,必须提供 bool 修饰符,这些操作符会根据比较结果返回另一个标量,值为 0 (假) 或 1 (真)。

在瞬时向量和标量之间,这些操作符应用于向量中每个数据样本的值,比较结果为 false 的向量元素将从结果向量中移除。这些操作只适用于向量中的浮点样本。对于直方图样本,相应的元素将从结果向量中移除,并由信息级别注释标记。

在两个瞬时向量之间,这些操作符默认作为过滤器,应用于匹配的条目。表达式不为真或在另一侧找不到匹配的向量元素将从结果中移除,而其他元素会被传递到结果向量中,分组标签成为输出标签集。两个浮点样本之间的匹配正常工作,而浮点样本和直方图样本之间的匹配是无效的。相应的元素将从结果向量中移除,并由信息级别注释标记。在两个直方图样本之间,==!= 按预期工作,但所有其他比较二元操作符再次无效。

在任何涉及向量的比较二元操作中,提供 bool 修饰符会按以下方式改变行为:将被移除的向量元素将改为具有值 0,而将被保留的向量元素将具有值 1。此外,指标名称会被移除。(注意,涉及直方图样本的无效操作仍然不会返回结果,而不是返回值 0。)

逻辑/集合二元操作符

这些逻辑/集合二元操作符仅定义在瞬时向量之间

  • and (交集)
  • or (并集)
  • unless (补集)

vector1 and vector2 的结果是一个向量,该向量包含 vector1 中那些在 vector2 中具有完全匹配标签集的元素。其他元素被移除。指标名称和值从左侧向量继承。

vector1 or vector2 的结果是一个向量,该向量包含 vector1 的所有原始元素(标签集 + 值),以及 vector2 中那些在 vector1 中没有匹配标签集的元素。

vector1 unless vector2 的结果是一个向量,该向量包含 vector1 中那些在 vector2 中没有完全匹配标签集的元素。两个向量中所有匹配的元素都被移除。

由于这些逻辑/集合二元操作符不与样本值交互,它们对浮点样本和直方图样本的工作方式相同。

向量匹配

向量之间的操作尝试为左侧向量中的每个条目在右侧向量中找到一个匹配元素。匹配行为有两种基本类型:一对一和多对一/一对多。

向量匹配关键词

这些向量匹配关键词允许在具有不同标签集的序列之间进行匹配

  • on
  • ignoring

提供给匹配关键词的标签列表将决定向量如何组合。示例可在一对一向量匹配多对一和一对多向量匹配中找到。

分组修饰符

这些分组修饰符启用多对一/一对多向量匹配

  • group_left
  • group_right

可以向分组修饰符提供标签列表,其中包含来自“一”侧的标签,以便包含在结果指标中。

多对一和一对多匹配是高级用例,应仔细考虑。通常,正确使用 ignoring(<labels>) 可以获得期望的结果。

分组修饰符只能用于比较算术操作。默认情况下,诸如 andunlessor 的操作会与右侧向量中的所有可能条目进行匹配。

一对一向量匹配

一对一匹配从操作的每一侧找到一个唯一的条目对。在默认情况下,格式遵循 vector1 <operator> 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),将不会有匹配,因为这些指标不共享相同的标签集。方法为 putdel 的条目没有匹配,不会出现在结果中。

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

多对一和一对多向量匹配

多对一一对多匹配指的是“一”侧的每个向量元素可以与“多”侧的多个元素匹配的情况。这必须通过使用 group_leftgroup_right 修饰符显式请求,其中 left/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

聚合操作符

Prometheus 支持以下内置聚合操作符,可用于聚合单个瞬时向量的元素,从而生成一个元素更少、值经过聚合的新向量

  • sum (计算维度上的总和)
  • avg (计算维度上的算术平均值)
  • min (选择维度上的最小值)
  • max (选择维度上的最大值)
  • bottomk (按样本值排序的最小 k 个元素)
  • topk (按样本值排序的最大 k 个元素)
  • limitk (抽样 k 个元素,实验性,必须启用 --enable-feature=promql-experimental-functions 功能标志)
  • limit_ratio (按伪随机比例 r 抽样元素,实验性,必须启用 --enable-feature=promql-experimental-functions 功能标志)
  • group (结果向量中的所有值为 1)
  • count (计算向量中的元素数量)
  • count_values (计算具有相同值的元素数量)

  • stddev (计算维度上的总体标准差)

  • stdvar (计算维度上的总体方差)

  • quantile (计算维度上的 φ 分位数 (0 ≤ φ ≤ 1))

这些操作符既可以用于聚合所有标签维度,也可以通过包含 withoutby 子句来保留特定维度。这些子句可以在表达式之前或之后使用。

<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)

<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]

label list 是一个不带引号的标签列表,可以包含末尾的逗号,例如 (label1, label2)(label1, label2,) 都是有效的语法。

without 从结果向量中移除列出的标签,而所有其他标签则保留在输出中。by 则相反,会移除未在 by 子句中列出的标签,即使这些标签的值在向量的所有元素之间是相同的。

parameter 只对 topkbottomklimitklimit_ratioquantilecount_values 需要。它分别用作 *k*、*r*、*φ* 的值或附加标签的名称。

详细解释

sum 以与 + 二元操作符在两个值之间相加的相同方式对样本值求和。类似地,avg 以与 / 二元操作符相同的方式将总和除以聚合的样本数量。因此,聚合到一个结果向量元素中的所有样本值必须要么是浮点样本,要么是直方图样本。混合两者的聚合是无效的,会导致相应的向量元素从输出向量中移除,并由警告级别(warn-level)注释标记。

minmax 只对浮点样本进行操作,遵循 IEEE 754 浮点算术,这意味着只有当所有聚合值都是 NaN 时,NaN 才被视为最小值或最大值。输入向量中的直方图样本会被忽略,并由信息级别注释标记。

topkbottomk 与其他聚合器不同之处在于,结果向量中返回的是输入样本的一个子集,包括原始标签。bywithout 仅用于对输入向量进行分桶。与 minmax 类似,它们只对浮点样本进行操作,分别将 NaN 值视为离顶部或底部最远的值。输入向量中的直方图样本会被忽略,并由信息级别注释标记。

如果在瞬时查询中使用,topkbottomk 分别按值降序或升序返回序列。如果与 bywithout 一起使用,则每个桶内的序列按值排序,同一桶中的序列会连续返回,但不保证桶之间的序列以任何特定顺序返回。范围查询不应用排序。

limitklimit_ratio 也返回输入样本的一个子集,包括结果向量中的原始标签。子集以确定性的伪随机方式选择。limitk 选择 *k* 个样本,而 limit_ratio 选择样本比例 *r*(每个都由参数确定)。这与样本类型无关。因此,它适用于浮点样本和直方图样本。*r* 的值可以在 +1 和 -1 之间。*r* 的绝对值用作选择比例,但对于负数 *r*,选择顺序会反转,这可用于选择补集。例如,limit_ratio(0.1, ...) 返回大约 10% 的输入样本的确定性集合,而 limit_ratio(-0.9, ...) 精确返回未由 limit_ratio(0.1, ...) 返回的剩余大约 90% 的输入样本。

groupcount 不与样本值交互,它们对浮点样本和直方图样本的工作方式相同。

count_values 为每个唯一的样本值输出一个时间序列。每个序列都有一个附加标签。该标签的名称由聚合参数给出,标签值是唯一的样本值。每个时间序列的值是该样本值出现的次数。count_values 对浮点样本和直方图样本都有效。对于后者,直方图样本值的紧凑字符串表示形式用作标签值。

stddevstdvar 只对浮点样本工作,遵循 IEEE 754 浮点算术。输入向量中的直方图样本会被忽略,并由信息级别注释标记。

quantile 计算 φ 分位数,即在聚合维度上的 N 个指标值中排名为 φ*N 的值。φ 作为聚合参数提供。例如,quantile(0.5, ...) 计算中位数,quantile(0.95, ...) 计算 95% 分位数。对于 φ = NaN,返回 NaN。对于 φ < 0,返回 -Inf。对于 φ > 1,返回 +Inf。

示例

如果指标 http_requests_total 有按 applicationinstancegroup 标签扇出的时间序列,我们可以通过以下方式计算每个 applicationgroup 在所有实例上看到的总 HTTP 请求数

sum without (instance) (http_requests_total)

这等同于

 sum by (application, group) (http_requests_total)

如果我们只关心在所有应用程序中看到的所有 HTTP 请求的总数,我们可以简单地写

sum(http_requests_total)

要计算运行每个构建版本的二进制文件的数量,我们可以写

count_values("version", build_version)

要获取所有实例中最大的 5 个 HTTP 请求计数,我们可以写

topk(5, http_requests_total)

要抽样 10 个时间序列,例如检查标签及其值,我们可以写

limitk(10, http_requests_total)

二元操作符优先级

以下列表显示了 Prometheus 中二元操作符的优先级,从高到低排列。

  1. ^
  2. *, /, %, atan2
  3. +, -
  4. ==, !=, <=, <, >=, >
  5. and, unless

同一优先级的操作符是左结合的。例如,2 * 3 % 2 等同于 (2 * 3) % 2。然而,^ 是右结合的,所以 2 ^ 3 ^ 2 等同于 2 ^ (3 ^ 2)

本文档是开源的。请通过提交 Issue 或 Pull Request 来帮助改进它。