运算符

PromQL 支持一元运算符、二元运算符和聚合运算符。

一元运算符

PromQL 中唯一的单目运算符是 - (单目减)。它可以应用于标量或即时向量。在前一种情况下,它返回符号相反的标量。在后一种情况下,它返回一个向量,其中每个元素的符号都相反。直方图样本的符号是通过反转所有存储桶的填充值、计数和观测总和的符号来实现的。结果直方图样本始终被视为量规直方图。

注意任何存储桶填充值为负或观测计数为负的直方图只能用作中间结果。如果此类负直方图是录制规则的最终结果,则规则评估将失败。负直方图无法通过任何交换格式(导出、远程写入、OTLP)表示,因此无法以任何方式摄取到 Prometheus 中,只能由 PromQL 表达式创建。

二元运算符

二元运算符涵盖基本的逻辑和算术运算。对于即时向量之间的运算,匹配行为可以修改。

算术二元运算符

PromQL 中存在以下算术二元运算符

  • + (加法)
  • - (减法)
  • * (乘法)
  • / (除法)
  • % (取模)
  • ^ (幂/指数)

算术二元运算符定义在标量/标量、向量/标量和向量/向量值对之间。它们遵循标准的 IEEE 754 浮点数算术 ,包括对 NaN+Inf-Inf 等特殊值的处理。

两个标量之间,行为很直接:它们计算为将运算符应用于两个标量操作数的结果的另一个标量。

即时向量和标量之间,运算符应用于向量中每个数据样本的值。

如果数据样本是浮点数,则在浮点数和标量之间执行运算。例如,如果一个浮点数样本的即时向量乘以 2,结果是另一个浮点数样本向量,其中原始向量的每个样本值都乘以 2。

对于是直方图样本的向量元素,行为如下:

  • 对于 *,所有存储桶填充值、计数和观测总和都乘以标量。如果标量为负,则结果直方图被视为量规直方图。否则,将保留输入直方图样本的计数器与量规的风格。

  • 对于 /,直方图样本必须位于左侧 (LHS),后面是右侧 (RHS) 的标量。然后,所有存储桶填充值、计数和观测总和都除以标量。除以零的结果是一个直方图,没有常规存储桶,并且零存储桶填充值、计数和观测总和都设置为 +Inf-InfNaN,具体取决于它们在输入直方图中的值(分别为正、负或零/NaN)。如果标量为负,则结果直方图被视为量规直方图。否则,将保留输入直方图样本的计数器与量规的风格。

  • 对于左侧为标量、右侧为直方图样本的 /,以及所有其他算术二元运算符在标量和直方图样本的任何组合中,没有结果,相应元素将从结果向量中移除。此类移除由信息级别注释标记。

两个即时向量之间,算术二元运算符应用于 LHS 向量中的每个条目及其在 RHS 向量中的匹配条目。结果将传播到结果向量中,分组标签成为输出标签集。未能在右侧向量中找到匹配条目的条目不包含在结果中。

如果两个浮点数样本匹配,则在两个输入值之间执行算术运算符。

如果浮点数样本与直方图样本匹配,则行为遵循与标量和直方图样本之间的逻辑相同(见上文),即 */(后者直方图样本在左侧)是有效运算,而所有其他运算会导致相应元素从结果向量中移除。

如果两个直方图样本匹配,只有 +- 是有效运算,它们分别将所有匹配的存储桶填充值、计数和观测总和相加或相减。所有其他运算都会导致相应元素从输出向量中移除,并由信息级别注释标记。+ 和 -` 运算通常只应用于量规直方图,但 PromQL 也允许将其用于计数器直方图,以覆盖特定用例,因此需要特别注意,以避免计数器重置不一致的问题。(PromQL 可以检测到计数器重置的某些不兼容性,并用警告级别注释标记。)将两个计数器直方图相加会产生一个计数器直方图。所有其他操作数组合以及所有减法都会产生量规直方图。

在任何涉及向量的算术二元运算中,度量名称将被丢弃。即使 __name__on 中被明确提及,也会发生这种情况(有关更多讨论,请参阅 https://github.com/prometheus/prometheus/issues/16631 )。

对于任何可能导致负直方图的算术二元运算,请考虑上面的相应说明

三角二元运算符

Prometheus 中存在以下以弧度为单位的三角二元运算符

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

比较二元运算符

Prometheus 中存在以下二元比较运算符

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

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

两个标量之间,必须提供 bool 修改符,这些运算符会计算为另一个标量,该标量是 0 (false) 或 1 (true),具体取决于比较结果。

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

两个即时向量之间,这些运算符默认行为是按匹配条目进行过滤。表达式不为 true 的向量元素或在表达式另一侧找不到匹配项的元素将被从结果中删除,而其他元素将传播到结果向量中,分组标签成为输出标签集。

两个浮点数样本之间的匹配按预期工作。

浮点数样本与直方图样本之间的匹配无效,相应元素将从结果向量中移除,并由信息级别注释标记。

在两个直方图样本之间,==!= 按预期工作,但所有其他比较二元运算再次无效。

在任何涉及向量的比较二元运算中,提供 bool 修改符会以以下方式改变行为:

  • 在表达式另一侧找到匹配项但表达式为 false 的向量元素将值设置为 0,而找到匹配项且表达式为 true 的向量元素的值为 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
  • 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 修饰符显式请求,其中左/右决定哪个向量具有更高的基数。

<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(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))

这些运算符既可以用于聚合所有标签维度,也可以通过包含 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 子句中未列出的标签,即使它们在向量的所有元素之间具有相同的值。

详细说明

sum

sum(v) 以与 + 二元运算符处理两个值的方式相同,对 v 中的样本值进行求和。

聚合到单个结果向量元素中的所有样本值必须是浮点数样本或直方图样本。混合这两种样本是无效的,将导致相应向量元素从输出向量中移除,并由警告级别注释标记。

示例

如果度量 memory_consumption_bytes 具有按 applicationinstancegroup 标签分叉的时间序列,我们可以通过以下方式计算每个应用程序和组的总内存消耗(跨所有实例):

sum without (instance) (memory_consumption_bytes)

这等同于

sum by (application, group) (memory_consumption_bytes)

如果我们只关心所有应用程序的总内存消耗,我们可以简单地写:

sum(memory_consumption_bytes)

avg

avg(v) 以与 / 二元运算符相同的方式,将 v 的总和除以聚合样本的数量。

聚合到单个结果向量元素中的所有样本值必须是浮点数样本或直方图样本。混合这两种样本是无效的,将导致相应向量元素从输出向量中移除,并由警告级别注释标记。

minmax

min(v)max(v) 分别返回 v 中的最小值或最大值。

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

topkbottomk

topk(k, v)bottomk(k, v) 与其他聚合器的不同之处在于,它们会返回输入样本的一个子集(包含原始标签),其中包含 k 个值。

bywithout 仅用于对输入向量进行分桶。

minmax 类似,它们仅对浮点数样本进行操作,并将 NaN 值视为最远离顶部或底部的值。输入向量中的直方图样本将被忽略,并由信息级别注释标记。

如果在即时查询中使用,topkbottomk 将按降序或升序返回按值排序的系列。如果与 bywithout 一起使用,则每个桶内的系列将按值排序,并且同一桶中的系列将连续返回,但不能保证桶的系列将按任何特定顺序返回。

范围查询不排序。

示例

要获取所有实例中内存消耗最高的 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 浮点算术。输入向量中的直方图样本将被忽略,并附带一个 info 级别注释。

stdvar

stdvar(v) 返回 v 的标准差。

stdvar 仅支持浮点类型样本,遵循 IEEE 754 浮点算术。输入向量中的直方图样本将被忽略,并附带一个 info 级别注释。

quantile

quantile(φ, v) 计算 φ 分位数,即在所有聚合的 N 个指标值中排在第 φ*N 位的值。

quantile 仅支持浮点类型样本。输入向量中的直方图样本将被忽略,并附带一个 info 级别注释。

NaN 被视为最小的可能值。

例如,quantile(0.5, ...) 计算中位数,quantile(0.95, ...) 计算 95 百分位数。

特殊情况

  • 当 φ 为 NaN 时,返回 NaN
  • 当 φ < 0 时,返回 -Inf
  • 当 φ > 1 时,返回 +Inf

二进制运算符优先级

以下列表显示了 Prometheus 中二进制运算符的优先级,从高到低。

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

相同优先级级别的运算符是左结合的。例如,2 * 3 % 2 等同于 (2 * 3) % 2。但是 ^ 是右结合的,所以 2 ^ 3 ^ 2 等同于 2 ^ (3 ^ 2)

本页内容