运算符
二元运算符
Prometheus 的查询语言支持基本的逻辑和算术运算符。对于两个即时向量之间的操作,可以修改匹配行为。
算术二元运算符
Prometheus 中存在以下二元算术运算符
+
(加法)-
(减法)*
(乘法)/
(除法)%
(模)^
(幂/指数)
二元算术运算符定义在标量/标量、向量/标量和向量/向量值对之间。它们遵循通常的IEEE 754 浮点算术,包括对 NaN
、+Inf
和 -Inf
等特殊值的处理。
在两个标量之间,行为是显而易见的:它们会计算为另一个标量,该标量是运算符应用于两个标量操作数的结果。
在即时向量和标量之间,运算符应用于向量中每个数据样本的值。如果数据样本是浮点数,则对数据样本执行的操作再次是显而易见的,例如,如果一个浮点样本的即时向量乘以 2,则结果是另一个浮点样本向量,其中原始向量的每个样本值都乘以 2。对于直方图样本的向量元素,行为如下:对于 *
,所有桶填充和观测值的计数和总和都乘以标量。对于 /
,直方图样本必须在左侧 (LHS),后面是右侧 (RHS) 的标量。然后所有桶填充和观测值的计数和总和都除以标量。除以零会导致直方图没有常规桶,并且零桶填充以及观测值的计数和总和都设置为 +Inf、-Inf 或 NaN,具体取决于它们在输入直方图中的值(分别为正、负或零/NaN)。对于左侧 (LHS) 是标量且右侧 (RHS) 是直方图样本的 /
,以及标量和直方图样本的任何其他算术二元运算符组合,都没有结果,并且相应的元素将从结果向量中删除。此类删除将通过信息级别的注解进行标记。
在两个即时向量之间,二元算术运算符应用于左侧向量中的每个条目及其在右侧向量中的匹配元素。结果将传播到结果向量中,分组标签成为输出标签集。在右侧向量中找不到匹配条目的条目不属于结果的一部分。如果两个浮点样本匹配,则行为显而易见。如果浮点样本与直方图样本匹配,则行为遵循与标量和直方图样本之间相同的逻辑(见上文),即 *
和 /
(后者以直方图样本在左侧)是有效操作,而所有其他操作都会导致相应元素从结果向量中移除。如果两个直方图样本匹配,则只有 +
和 -
是有效操作,分别添加或减去所有匹配的桶填充以及观测值的计数和总和。所有其他操作都会导致相应元素从输出向量中移除,并通过信息级别的注解进行标记。
在任何涉及向量的算术二元操作中,指标名称都会被丢弃。
三角二元运算符
Prometheus 中存在以下以弧度为单位的三角二元运算符
atan2
(基于 https://pkg.go.dev/math#Atan2)
三角运算符允许使用向量匹配在两个向量上执行三角函数,这在普通函数中是不可用的。它们的行为方式与算术运算符相同。它们仅对浮点样本进行操作。涉及直方图样本的操作会导致相应的向量元素从输出向量中移除,并通过信息级别的注解进行标记。
比较二元运算符
Prometheus 中存在以下二元比较运算符
==
(等于)!=
(不等于)>
(大于)<
(小于)>=
(大于或等于)<=
(小于或等于)
比较运算符定义在标量/标量、向量/标量和向量/向量值对之间。默认情况下,它们执行过滤。通过在运算符后提供 bool
可以修改它们的行为,这将为值返回 0
或 1
而不是过滤。
在两个标量之间,必须提供 bool
修饰符,这些运算符会产生另一个标量,该标量是 0
(false
) 或 1
(true
),具体取决于比较结果。
在即时向量和标量之间,这些运算符应用于向量中每个数据样本的值,并且比较结果为 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>)
可以达到所需的结果。
分组修饰符只能用于比较和算术操作。默认情况下,and
、unless
和 or
等操作会匹配右侧向量中的所有可能条目。
一对一向量匹配
一对一从操作的每一侧找到唯一的一对条目。在默认情况下,这是一种遵循 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)
,则不会有匹配项,因为这些指标不共享相同的标签集。方法为 put
和 del
的条目没有匹配项,将不会出现在结果中。
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
多对一和一对多向量匹配
多对一和一对多匹配指的是“一”侧的每个向量元素可以与“多”侧的多个元素匹配的情况。这必须使用 group_left
或 group_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))
这些运算符既可以用于聚合所有标签维度,也可以通过包含 without
或 by
子句来保留不同的维度。这些子句可以在表达式之前或之后使用。
<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)
或
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
标签列表
是一个不带引号的标签列表,可能包含一个尾随逗号,即 (label1, label2)
和 (label1, label2,)
都是有效的语法。
without
从结果向量中移除列出的标签,而所有其他标签在输出中得以保留。by
则相反,它会删除未在 by
子句中列出的标签,即使它们的标签值在向量的所有元素之间是相同的。
parameter
仅适用于 topk
、bottomk
、limitk
、limit_ratio
、quantile
和 count_values
。它分别用作 k、r、φ 或附加标签的名称的值。
详细说明
sum
以与 +
二元运算符在两个值之间相同的方式对样本值求和。类似地,avg
以与 /
二元运算符相同的方式将总和除以聚合样本的数量。因此,聚合到单个结果向量元素中的所有样本值必须是浮点样本或直方图样本。两者的混合聚合是无效的,会导致相应的向量元素从输出向量中移除,并通过警告级别的注解进行标记。
min
和 max
仅对浮点样本进行操作,遵循 IEEE 754 浮点算术,这尤其意味着只有当所有聚合值都为 NaN
时,NaN
才被视为最小值或最大值。输入向量中的直方图样本将被忽略,并通过信息级别的注解进行标记。
topk
和 bottomk
与其他聚合器不同之处在于,结果向量中会返回输入样本的子集,包括原始标签。by
和 without
仅用于对输入向量进行分桶。与 min
和 max
类似,它们只对浮点样本进行操作,将 NaN
值分别视为离顶部或底部最远。输入向量中的直方图样本将被忽略,并通过信息级别的注解进行标记。
如果在即时查询中使用,topk
和 bottomk
会分别按值降序或升序返回序列。如果与 by
或 without
一起使用,则每个桶内的序列将按值排序,并且同一桶中的序列将连续返回,但不能保证系列桶会按任何特定顺序返回。范围查询不适用任何排序。
limitk
和 limit_ratio
也返回输入样本的子集,包括结果向量中的原始标签。子集以确定性的伪随机方式选择。limitk
选择 k 个样本,而 limit_ratio
选择样本的比例 r(每个由 parameter
决定)。这与样本类型无关。因此,它适用于浮点样本和直方图样本。r 的取值范围可以在 +1 和 -1 之间。r 的绝对值用作选择比例,但对于负 r,选择顺序是颠倒的,这可以用于选择补集。例如,limit_ratio(0.1, ...)
返回大约 10% 的输入样本的确定性集合,而 limit_ratio(-0.9, ...)
精确返回 limit_ratio(0.1, ...)
未返回的剩余大约 90% 的输入样本。
group
和 count
不与样本值交互,它们对浮点样本和直方图样本的工作方式相同。
count_values
为每个唯一的样本值输出一个时间序列。每个序列都有一个附加标签。该标签的名称由聚合参数给出,标签值是唯一的样本值。每个时间序列的值是该样本值出现的次数。count_values
适用于浮点样本和直方图样本。对于后者,直方图样本值的紧凑字符串表示形式用作标签值。
stddev
和 stdvar
仅对浮点样本进行操作,遵循 IEEE 754 浮点算术。输入向量中的直方图样本将被忽略,并通过信息级别的注解进行标记。
quantile
计算 φ 分位数,即在聚合维度上的 N 个指标值中排名 φ*N 的值。φ 作为聚合参数提供。例如,quantile(0.5, ...)
计算中位数,quantile(0.95, ...)
计算 95 百分位。对于 φ = NaN
,返回 NaN
。对于 φ < 0,返回 -Inf
。对于 φ > 1,返回 +Inf
。
示例
如果指标 http_requests_total
包含按 application
、instance
和 group
标签展开的时间序列,我们可以通过以下方式计算每个应用程序和组在所有实例上观察到的 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 中二元运算符的优先级,从高到低。
^
*
、/
、%
、atan2
+
,-
==
,!=
,<=
,<
,>=
,>
and
、unless
或
相同优先级的运算符是左结合的。例如,2 * 3 % 2
等效于 (2 * 3) % 2
。然而 ^
是右结合的,所以 2 ^ 3 ^ 2
等效于 2 ^ (3 ^ 2)
。