聚合
您可以使用聚合:
- 在摄取规范中,以便在数据进入 Apache Druid 之前对其进行汇总。
- 在查询时,以便汇总结果数据。
以下部分列出了可用的聚合函数。除非另有说明,聚合均可在摄取时和查询时使用。
精确聚合
Count 聚合器
count 计算与过滤器匹配的 Druid 行数。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "count"。 | 是 |
name | 聚合器的输出名称 | 是 |
示例
{ "type" : "count", "name" : "count" }
count 聚合器计算的是 Druid 的行数,这并不总是等于摄取的原始事件数量。这是因为 Druid 可以配置为在摄取时进行汇总(Rollup)。要计算摄取的原始数据行数,请在摄取时包含一个 count 聚合器,并在查询时使用 longSum 聚合器。
Sum 聚合器
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "longSum"、"doubleSum" 或 "floatSum"。 | 是 |
name | 求和值的输出名称。 | 是 |
fieldName | 要进行求和的输入列名。 | 否。您必须指定 fieldName 或 expression。 |
expression | 您可以指定一个内联 表达式 作为 fieldName 的替代方案。 | 否。您必须指定 fieldName 或 expression。 |
longSum 聚合器
将值的总和计算为 64 位有符号整数。
示例
{ "type" : "longSum", "name" : "sumLong", "fieldName" : "aLong" }
doubleSum 聚合器
将值的总和计算并存储为 64 位浮点值。类似于 longSum。
示例
{ "type" : "doubleSum", "name" : "sumDouble", "fieldName" : "aDouble" }
floatSum 聚合器
将值的总和计算并存储为 32 位浮点值。类似于 longSum 和 doubleSum。
示例
{ "type" : "floatSum", "name" : "sumFloat", "fieldName" : "aFloat" }
Min 和 max 聚合器
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "doubleMin"、"doubleMax"、"floatMin"、"floatMax"、"longMin" 或 "longMax"。 | 是 |
name | 最小值或最大值的输出名称。 | 是 |
fieldName | 要计算最小值或最大值的输入列名。 | 否。您必须指定 fieldName 或 expression。 |
expression | 您可以指定一个内联 表达式 作为 fieldName 的替代方案。 | 否。您必须指定 fieldName 或 expression。 |
doubleMin 聚合器
doubleMin 计算所有输入值和 null 的最小值。
示例
{ "type" : "doubleMin", "name" : "maxDouble", "fieldName" : "aDouble" }
doubleMax 聚合器
doubleMax 计算所有输入值和 null 的最大值。
示例
{ "type" : "doubleMax", "name" : "minDouble", "fieldName" : "aDouble" }
floatMin 聚合器
floatMin 计算所有输入值和 null 的最小值。
示例
{ "type" : "floatMin", "name" : "minFloat", "fieldName" : "aFloat" }
floatMax 聚合器
floatMax 计算所有输入值和 null 的最大值。
示例
{ "type" : "floatMax", "name" : "maxFloat", "fieldName" : "aFloat" }
longMin 聚合器
longMin 计算所有输入值和 null 的最小值。
示例
{ "type" : "longMin", "name" : "minLong", "fieldName" : "aLong" }
longMax 聚合器
longMax 计算所有指标值和 null 的最大值。
示例
{ "type" : "longMax", "name" : "maxLong", "fieldName" : "aLong" }
doubleMean 聚合器
计算并返回列值的算术平均值,结果为 64 位浮点值。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "doubleMean"。 | 是 |
name | 平均值的输出名称。 | 是 |
fieldName | 要计算算术平均值的输入列名。 | 是 |
示例
{ "type" : "doubleMean", "name" : "aMean", "fieldName" : "aDouble" }
doubleMean 仅限查询时使用。它不适用于索引(摄取)阶段。若要在摄取时实现平均值聚合,请参考 DataSketches 扩展中的 分位数 (Quantiles) 聚合器。
First 和 last 聚合器
First 和 last 聚合器确定时间列最早和最新值对应的指标值。
在启用了汇总(rollup)的段(segment)上使用 first 或 last 聚合器的查询,返回的是汇总后的值,而不是原始摄取数据中的第一个或最后一个值。在这种情况下,timeColumn 将被忽略,聚合将使用段创建时存储的原始时间列值。
数值型 first 和 last 聚合器
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "doubleFirst"、"doubleLast"、"floatFirst"、"floatLast"、"longFirst"、"longLast"。 | 是 |
name | 第一个或最后一个值的输出名称。 | 是 |
fieldName | 要计算第一个或最后一个值的输入列名。 | 是 |
timeColumn | 用于时间值的输入列名。必须是 LONG 类型列。 | 否。默认为 __time。 |
doubleFirst 聚合器
doubleFirst 计算时间列最小值对应的输入值;如果不存在对应行,默认模式返回 0,SQL 兼容模式返回 null。
示例
{
"type" : "doubleFirst",
"name" : "firstDouble",
"fieldName" : "aDouble"
}
doubleLast 聚合器
doubleLast 计算时间列最大值对应的输入值;如果不存在对应行,默认模式返回 0,SQL 兼容模式返回 null。
示例
{
"type" : "doubleLast",
"name" : "lastDouble",
"fieldName" : "aDouble",
"timeColumn" : "longTime"
}
floatFirst 聚合器
floatFirst 计算时间列最小值对应的输入值;如果不存在对应行,默认模式返回 0,SQL 兼容模式返回 null。
示例
{
"type" : "floatFirst",
"name" : "firstFloat",
"fieldName" : "aFloat"
}
floatLast 聚合器
floatLast 计算时间列最大值对应的指标值;如果不存在对应行,默认模式返回 0,SQL 兼容模式返回 null。
示例
{
"type" : "floatLast",
"name" : "lastFloat",
"fieldName" : "aFloat"
}
longFirst 聚合器
longFirst 计算时间列最小值对应的指标值;如果不存在对应行,默认模式返回 0,SQL 兼容模式返回 null。
示例
{
"type" : "longFirst",
"name" : "firstLong",
"fieldName" : "aLong"
}
longLast 聚合器
longLast 计算时间列最大值对应的指标值;如果不存在对应行,默认模式返回 0,SQL 兼容模式返回 null。
示例
{
"type" : "longLast",
"name" : "lastLong",
"fieldName" : "aLong",
"timeColumn" : "longTime"
}
字符串型 first 和 last 聚合器
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "stringFirst"、"stringLast"。 | 是 |
name | 第一个或最后一个值的输出名称。 | 是 |
fieldName | 要计算第一个或最后一个值的输入列名。 | 是 |
timeColumn | 用于时间值的输入列名。必须是 LONG 类型列。 | 否。默认为 __time。 |
maxStringBytes | 计算每组的第一个或最后一个值时,要累积的字符串值的最大大小。超过此长度的值将被截断。 | 否。默认为 1024。 |
stringFirst 聚合器
stringFirst 计算时间列最小值对应的指标值;如果不存在对应行,返回 null。
示例
{
"type" : "stringFirst",
"name" : "firstString",
"fieldName" : "aString",
"maxStringBytes" : 2048,
"timeColumn" : "longTime"
}
stringLast 聚合器
stringLast 计算时间列最大值对应的指标值;如果不存在对应行,返回 null。
示例
{
"type" : "stringLast",
"name" : "lastString",
"fieldName" : "aString"
}
ANY 聚合器
(Double/Float/Long/String) ANY 聚合器不能用于摄取规范中,只能作为查询的一部分指定。
返回任意值(包括 null)。此聚合器通过返回遇到的第一个值(包括 null)来简化并优化性能。
数值型 any 聚合器
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "doubleAny"、"floatAny" 或 "longAny"。 | 是 |
name | 值的输出名称。 | 是 |
fieldName | 要计算值的输入列名。 | 是 |
doubleAny 聚合器
doubleAny 返回任意 double 型指标值。
示例
{
"type" : "doubleAny",
"name" : "anyDouble",
"fieldName" : "aDouble"
}
floatAny 聚合器
floatAny 返回任意 float 型指标值。
示例
{
"type" : "floatAny",
"name" : "anyFloat",
"fieldName" : "aFloat"
}
longAny 聚合器
longAny 返回任意 long 型指标值。
示例
{
"type" : "longAny",
"name" : "anyLong",
"fieldName" : "aLong"
}
stringAny 聚合器
stringAny 返回输入中存在的任意字符串值。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "stringAny"。 | 是 |
name | 值的输出名称。 | 是 |
fieldName | 要计算值的输入列名。 | 是 |
maxStringBytes | 计算每组的第一个或最后一个值时,要累积的字符串值的最大大小。超过此长度的值将被截断。 | 否。默认为 1024。 |
aggregateMultipleValues | aggregateMultipleValues 是一个可选的布尔标志,用于控制聚合 多值维度 的行为。默认值为 true,在处理多值维度时返回字符串化数组。设置为 false 时,函数将返回第一个值。 | 否。默认为 true。 |
示例
{
"type" : "stringAny",
"name" : "anyString",
"fieldName" : "aString",
"maxStringBytes" : 2048
}
近似聚合
Count distinct (去重计数)
Apache DataSketches Theta Sketch
DataSketches Theta Sketch 扩展提供的聚合器可提供去重计数估计,并支持使用 Apache DataSketches 库中的 Theta Sketch 进行集合并集、交集和差集后聚合。
Apache DataSketches HLL Sketch
DataSketches HLL Sketch 扩展提供的聚合器使用 HyperLogLog 算法提供去重计数估计。
与 Theta Sketch 相比,HLL Sketch 不支持集合运算,更新和合并速度稍慢,但所需的空间显著较小。
Cardinality, hyperUnique
对于新用例,我们建议优先评估 DataSketches Theta Sketch 或 DataSketches HLL Sketch。DataSketches 聚合器通常比 Druid 经典的 cardinality 和 hyperUnique 聚合器具有更高的灵活性和准确性。
Cardinality 和 HyperUnique 聚合器是 Druid 默认提供的旧版实现,同样使用 HyperLogLog 算法提供去重计数估计。上述提到的更新后的 DataSketches Theta 和 HLL 扩展聚合器具有更优的准确性和性能,因此更推荐使用。
DataSketches 团队发布了一份 对比研究,涵盖了 Druid 原始 HLL 算法与 DataSketches HLL 算法。基于 DataSketches 实现的明显优势,我们建议优先使用它们,而非 Druid 原始的 HLL 聚合器。不过,为确保向后兼容性,我们将继续支持经典聚合器。
请注意,hyperUnique 聚合器与 Datasketches HLL 或 Theta Sketch 不兼容。
多列处理
请注意,DataSketches Theta 和 HLL 聚合器目前仅支持单列输入。如果您之前使用 Cardinality 聚合器处理多列输入,下面描述了使用 Theta 或 HLL Sketch 进行等效操作的方法:
- 多列
byValueCardinality 可以被单个输入列上的 Theta Sketch 并集所替代。 - 多列
byRowCardinality 可以被单个 虚拟列 上的 Theta 或 HLL Sketch 所替代,该虚拟列结合了各个输入列。
直方图和分位数
DataSketches Quantiles Sketch
DataSketches Quantiles Sketch 扩展提供的聚合器使用来自 datasketches 库的数字分位数 DoublesSketch 提供分位数估计和直方图近似。
通常我们推荐该聚合器用于分位数/直方图用例,因为它提供了正式的误差界限,且精度与分布无关。
Moments Sketch (实验性)
Moments Sketch 扩展提供的聚合器是一个实验性聚合器,它使用 Moments Sketch 提供分位数估计。
Moments Sketch 聚合器是作为实验选项提供的。它针对合并速度进行了优化,聚合性能可能高于 DataSketches 分位数聚合器。但 Moments Sketch 的准确性取决于数据分布,因此用户需要通过实验验证该聚合器是否适用于其输入数据。
作为实验的一般指导原则,Moments Sketch 论文 指出,该算法在高熵输入上表现更好。特别是当输入数据由少量聚类的离散值组成时,该算法不太适用。
固定桶直方图 (Fixed Buckets Histogram)
Druid 还提供了一个 简单的直方图实现,它使用固定的范围和固定数量的桶,支持分位数估计,并由桶计数数组支持。
当输入数据的分布允许使用少量桶时,固定桶直方图可以表现良好。
我们不建议一般用途使用固定桶直方图,因为其实用性极大地依赖于数据。不过,它为已经确定固定桶直方图适合其用例的用户提供。
近似直方图 (Approximate Histogram) (已弃用)
Approximate Histogram 聚合器已弃用。目前有许多其他提供更好性能、准确性和内存占用的分位数估计算法。我们建议改用 DataSketches Quantiles。
Approximate Histogram 扩展提供的聚合器也提供分位数估计和直方图近似,基于 https://jmlr.org.cn/papers/volume11/ben-haim10a/ben-haim10a.pdf。
该弃用聚合器使用的算法高度依赖于分布,并且当输入不符合算法的限制时,其输出会受到严重失真。
DataSketches 团队发布的一项研究 展示了该算法的一些已知失败模式。
- 该算法的分位数计算可能无法为大范围的秩值提供结果(研究示例中所有低于 0.89 的秩都失效),取而代之返回所有零。
- 该算法可能完全无法记录分布尾部的峰值。
- 通常,该算法生成的直方图可能与真实直方图存在显著偏差,且没有误差范围保证。
无法预先确定此聚合器对于给定输入流的行为表现如何,聚合器也不会提供任何迹象表明输出存在严重失真。
基于这些原因,我们弃用了此聚合器,并建议在新的和现有的用例中使用 DataSketches Quantiles 聚合器,不过我们将继续支持 Approximate Histogram 以实现向后兼容性。
表达式聚合
Expression 聚合器
仅在查询时可用的聚合器。使用 Druid 表达式 函数聚合结果,以促进构建自定义函数。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "expression"。 | 是 |
name | 聚合器输出名称。 | 是 |
fields | 聚合器输入列列表。 | 是 |
accumulatorIdentifier | 在 fold 和 combine 表达式中标识累加器值的变量。 | 否。默认为 __acc。 |
fold | 用于从 fields 累加值的表达式。表达式的结果存储在 accumulatorIdentifier 中,并可供下一次计算使用。 | 是 |
combine | 在合并结果时组合每个段的各种 fold 表达式结果的表达式。输入作为变量(标识为 name)提供给表达式。 | 否。如果表达式在 fields 中只有一个输入,则默认为 fold 表达式。 |
compare | 比较器表达式,只能引用两个输入变量 o1 和 o2,其中 o1 和 o2 是 fold 或 combine 表达式的输出,并且必须遵守 Java 比较器契约。如果未设置,聚合器将尝试回退到适合输出类型的比较器。 | 否 |
finalize | 最终化表达式,只能引用单个输入变量 o。此表达式用于对 fold 或 combine 表达式的输出执行任何最终转换。如果未设置,则值不会被转换。 | 否 |
initialValue | fold(以及 combine,如果 InitialCombineValue 为 null)表达式的累加器初始值。 | 是 |
initialCombineValue | combine 表达式的累加器初始值。 | 否。默认为 initialValue。 |
isNullUnlessAggregated | 如果为 true,当聚合器不处理任何行时,将默认输出值设置为 null。如果为 false,Druid 将计算使用初始值运行表达式的结果作为值。 | 否。默认为 true。 |
shouldAggregateNullInputs | 指示 fold 表达式是否应处理任何 null 输入值。 | 否。默认为 true。 |
shouldCombineAggregateNullInputs | 指示 combine 表达式是否应处理任何 null 输入值。 | 否。默认为 shouldAggregateNullInputs 的值。 |
maxSizeBytes | 可变大小聚合器输出类型(如字符串和数组)在聚合失败前允许增长到的最大字节数。 | 否。默认值为 8192 字节。 |
示例:“count”聚合器
初始值为 0。fold 为处理的每一行添加 1。
{
"type": "expression",
"name": "expression_count",
"fields": [],
"initialValue": "0",
"fold": "__acc + 1",
"combine": "__acc + expression_count"
}
示例:“sum”聚合器
初始值为 0。fold 为处理的每一行添加 column_a 的数值。
{
"type": "expression",
"name": "expression_sum",
"fields": ["column_a"],
"initialValue": "0",
"fold": "__acc + column_a"
}
示例:“distinct array element”聚合器,按 array_length 排序
初始值为空数组。fold 使用集合语义将 column_a 的元素添加到累加器,combine 合并集合,compare 按 array_length 对值进行排序。
{
"type": "expression",
"name": "expression_array_agg_distinct",
"fields": ["column_a"],
"initialValue": "[]",
"fold": "array_set_add(__acc, column_a)",
"combine": "array_set_add_all(__acc, expression_array_agg_distinct)",
"compare": "if(array_length(o1) > array_length(o2), 1, if (array_length(o1) == array_length(o2), 0, -1))"
}
示例:使用内置 hyper-unique 的“近似计数”聚合器
类似于 cardinality 聚合器,默认值为空 hyper-unique sketch,fold 将 column_a 的值添加到 sketch 中,combine 合并 sketch,finalize 从累加的 sketch 中获取估计计数。
{
"type": "expression",
"name": "expression_cardinality",
"fields": ["column_a"],
"initialValue": "hyper_unique()",
"fold": "hyper_unique_add(column_a, __acc)",
"combine": "hyper_unique_add(expression_cardinality, __acc)",
"finalize": "hyper_unique_estimate(o)"
}
JavaScript 聚合器
在列集(允许指标和维度)上计算任意 JavaScript 函数。您的 JavaScript 函数预期返回浮点值。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "javascript"。 | 是 |
name | 聚合器输出名称。 | 是 |
fieldNames | 聚合器输入列列表。 | 是 |
fnAggregate | JavaScript 函数,根据当前行值更新部分聚合,并返回更新后的部分聚合。 | 是 |
fnCombine | 合并部分聚合并返回合并结果的 JavaScript 函数。 | 是 |
fnReset | 返回“初始”值的 JavaScript 函数。 | 是 |
示例
{
"type": "javascript",
"name": "sum(log(x)*y) + 10",
"fieldNames": ["x", "y"],
"fnAggregate" : "function(current, a, b) { return current + (Math.log(a) * b); }",
"fnCombine" : "function(partialA, partialB) { return partialA + partialB; }",
"fnReset" : "function() { return 10; }"
}
JavaScript 功能默认处于禁用状态。请参阅 Druid JavaScript 编程指南 以获取有关使用 Druid JavaScript 功能的指南,包括如何启用它的说明。
其他聚合
Filtered 聚合器
Filtered 聚合器包装了任何给定的聚合器,但仅聚合给定维度过滤器匹配的值。
这使得同时计算过滤和未过滤聚合的结果成为可能,而无需发出多次查询,并将两个结果用作后聚合的一部分。
如果只需要过滤结果,请考虑在查询本身上放置过滤器。这将快得多,因为它不需要扫描所有数据。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "filtered"。 | 是 |
name | 聚合器输出名称。 | 否 |
aggregator | 内联聚合器规范。 | 是 |
filter | 内联 过滤器 规范。 | 是 |
示例
{
"type": "filtered",
"name": "filteredSumLong",
"filter": {
"type" : "selector",
"dimension" : "someColumn",
"value" : "abcdef"
},
"aggregator": {
"type": "longSum",
"name": "sumLong",
"fieldName": "aLong"
}
}
Grouping 聚合器
Grouping 聚合器只能作为包含小计规范(subtotal spec)的 GroupBy 查询的一部分使用。它为每个输出行返回一个数字,允许您推断特定维度是否包含在该行使用的小组(sub-grouping)中。您可以将一个 非空 维度列表传递给此聚合器,该列表 必须 是您正在分组的维度的子集。
| 属性 | 描述 | 是否必须 |
|---|---|---|
type | 必须为 "grouping"。 | 是 |
name | 聚合器输出名称。 | 是 |
groupings | 用于分组集中的列列表。 | 是 |
例如,以下聚合器具有 ["dim1", "dim2"] 作为输入维度
{ "type" : "grouping", "name" : "someGrouping", "groupings" : ["dim1", "dim2"] }
并且在具有 [["dim1", "dim2"], ["dim1"], ["dim2"], []] 作为小计的分组查询中使用,聚合器的可能输出是
| 查询中使用的小计 | 输出 | (位表示) |
|---|---|---|
["dim1", "dim2"] | 0 | (00) |
["dim1"] | 1 | (01) |
["dim2"] | 2 | (10) |
[] | 3 | (11) |
正如示例所示,您可以将输出数字视为无符号的 n 位数字,其中 n 是传递给聚合器的维度数量。如果小组包含位置 X 处的维度,Druid 将数字中位置 X 处的位设置为 0。否则,Druid 将此位设置为 1。