操作符

PromQL 支持一元、二元和聚合操作符。

一元操作符

PromQL 中唯一的一元操作符是 -(一元减号)。它可以应用于标量或瞬时向量。在前者的情况下,它返回一个符号反转的标量。在后者的情况下,它返回一个瞬时向量,其中每个元素的符号都被反转。直方图样本的符号通过反转所有桶计数值、观察总数和观察总和来反转。产生的直方图样本始终被视为仪表直方图(gauge histogram)。

注意具有任何负桶计数值或负观察总数的直方图只能作为中间结果。如果这样的负直方图是记录规则的最终结果,则规则评估将失败。负直方图无法由任何交换格式(暴露格式、远程写入、OTLP)表示,因此它们无法以任何方式摄取到 Prometheus 中,只能由 PromQL 表达式创建。

二元操作符

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

算术二元操作符

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

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

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

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

在瞬时向量和标量之间,操作符被应用于向量中每个数据样本的值。

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

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

  • 对于 *,所有桶计数值、观察总数和观察总和都乘以该标量。如果标量为负,则生成的直方图被视为仪表直方图。否则,保留输入直方图样本的计数器(counter)或仪表(gauge)特性。

  • 对于 /,直方图样本必须在左侧 (LHS),标量在右侧 (RHS)。所有桶计数值、观察总数和观察总和都除以该标量。除以零会导致一个没有常规桶、且零桶计数值、观察总数和观察总和均设为 +Inf-InfNaN 的直方图(取决于它们在输入直方图中的值,分别是正数、负数或零/NaN)。如果标量为负,则生成的直方图被视为仪表直方图。否则,保留输入直方图样本的计数器或仪表特性。

  • 对于标量在左侧而直方图样本在右侧的 / 运算,以及所有其他标量和直方图样本组合的算术二元运算,没有结果,相应的元素将从结果向量中移除。这种移除会被信息级别的注解标记。

在两个瞬时向量之间,二元算术操作符被应用于左侧向量中的每个条目及其在右侧向量中的匹配元素。结果被传播到结果向量中,分组标签成为输出标签集。默认情况下,在对面向量中找不到匹配项的系列不会成为结果的一部分。这种行为可以使用填充修饰符进行调整。

如果匹配两个浮点样本,则将算术操作符应用于这两个输入值。

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

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

在涉及向量的任何算术二元运算中,指标名称会被丢弃。即使 __name__on 中被明确提及,也会发生这种情况(详见 https://github.com/prometheus/prometheus/issues/16631 )。

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

三角二元操作符

Prometheus 中存在以下三角二元操作符(以弧度为单位)

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

直方图裁剪操作符

Prometheus 中存在以下二元直方图裁剪操作符

  • </(上端裁剪):移除阈值以上的所有观察值
  • >/(下端裁剪):移除阈值以下的所有观察值

直方图裁剪操作符定义在向量/标量和向量/向量的值对之间,其中左侧是原生直方图(指数或 NHCB),右侧是浮点阈值。

如果阈值未与直方图的某个桶边界对齐,则应用线性插值(对于 NHCB 和指数直方图的零桶)或指数插值(对于指数直方图的非零桶)来计算包含阈值的桶中剩余的估计观察次数。

如果裁剪了一些观察值,则会根据剩余观察值重新计算(近似)新的观察值总和。

比较二元操作符

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

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

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

在两个标量之间,必须提供 bool 修饰符,这些操作符的结果是另一个标量,根据比较结果,要么是 0false),要么是 1true)。

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

在两个瞬时向量之间,这些操作符默认表现为过滤器,应用于匹配的条目。表达式不为真或在表达式另一侧找不到匹配项的向量元素将从结果中丢弃,而其他元素被传播到结果向量中,分组标签成为输出标签集。

两个浮点样本之间的匹配正常工作。

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

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

在涉及向量的任何比较二元运算中,提供 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(<label list>):仅在提供的标签上匹配。
  • ignoring(<label list>):匹配时忽略提供的标签。

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

组修饰符

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

  • group_left:允许进行多对一匹配,其中左侧向量具有更高的基数。
  • group_right:允许进行一对多匹配,其中右侧向量具有更高的基数。

可以将标签列表传递给组修饰符,其中包含来自“一”侧的标签,这些标签将被包含在结果指标中。

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

分组修饰符仅可用于比较算术三角操作符。集合操作符默认匹配两侧的所有可能条目。

一对一向量匹配

一对一从操作的两侧查找唯一的条目对。在默认情况下,即遵循格式 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

这会返回一个结果向量,包含每个方法的状态码为 500 的 HTTP 请求占比,基于过去 5 分钟的测量结果。如果没有 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

填充缺失的匹配项

填充修饰符是实验性的,必须通过 --enable-feature=promql-binop-fill-modifiers 启用。

默认情况下,在二元运算的另一侧找不到匹配的向量元素不会包含在结果向量中。填充修饰符允许通过使用提供的默认样本值填充二元运算任一侧的缺失系列来覆盖此行为。

  • fill(<value>):使用 value 填充任一侧缺失的匹配项。
  • fill_left(<value>):使用 value 填充左侧缺失的匹配项。
  • fill_right(<value>):使用 value 填充右侧缺失的匹配项。

value 必须是代表浮点样本的数值文字。不支持直方图样本。

注意,这些修饰符只能填充在运算的一侧缺失的系列。如果某个系列在两侧都缺失,则这些修饰符无法创建它。

填充修饰符可以按以下方式组合使用:

  • fill(<default>)
  • fill_left(<default>)
  • fill_right(<default>)
  • fill_left(<default>) fill_right(<default>)
  • fill_right(<default>) fill_left(<default>)

如果使用了其他二元操作符修饰符(如 boolonignoringgroup_leftgroup_right),则填充修饰符必须最后提供。

当填充修饰符与 group_leftgroup_right 结合使用时,其行为如下:

  • 如果填充修饰符用于匹配的“多”侧,它只会为每个匹配组的“多”侧填充一个序列,并使用该组的匹配标签作为序列标识。
  • 如果填充修饰符用于匹配的“一”侧,且分组修饰符指定了要从“一”侧包含的标签名称(例如 left_vector * on(instance, job) group_left(info_label) fill_right(1) right_vector),则缺失系列的这些标签不会被填充,因为没有它们的取值来源。

集合操作符(andorunless)不支持填充修饰符,因为这些操作符的目的是根据在另一个向量中的存在与否来过滤序列。

查询示例,用 0 填充任一侧缺失的系列。

method_code:http_errors:rate5m{status="500"} / ignoring(code) fill(0) method:http_requests:rate5m

这会返回一个结果向量,包含每个方法的状态码为 500 的 HTTP 请求占比,基于过去 5 分钟的测量结果。现在,方法为 putdel 的条目包含在结果中,并以 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))

这些操作符既可以用于聚合所有标签维度,也可以通过包含 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 浮点算术的浮点样本。输入向量中的直方图样本将被忽略,并伴随信息级别的注释标记。

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 中二元运算符的优先级,从高到低排列。

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

处于相同优先级的运算符具有左结合性。例如,2 * 3 % 2 等价于 (2 * 3) % 2。然而,^ 是右结合的,因此 2 ^ 3 ^ 2 等价于 2 ^ (3 ^ 2)

本页内容