跳转到主要内容
NumericIndexedVector 是一种抽象数据结构,用于封装向量,并支持向量聚合和按元素操作。其存储方式为 Bit-Sliced Index。有关其理论基础和适用场景,请参阅论文 Large-Scale Metric Computation in Online Controlled Experiment Platform

BSI

在 BSI (Bit-Sliced Index) 存储方法中,数据会以 Bit-Sliced Index 的形式存储,再使用 Roaring Bitmap 进行压缩。聚合操作和按元素操作都直接作用于压缩后的数据,因此可以显著提升存储和查询效率。 一个向量包含索引及其对应的值。以下是在 BSI 存储模式下,这种数据结构的一些特性和约束:
  • 索引类型只能是 UInt8UInt16UInt32 之一。注意: 考虑到 Roaring Bitmap 在 64 位实现下的性能,BSI 格式不支持 UInt64/Int64
  • 值类型可以是 Int8Int16Int32Int64UInt8UInt16UInt32UInt64Float32Float64 之一。注意: 值类型不会自动扩展。例如,如果使用 UInt8 作为值类型,任何超过 UInt8 容量的求和都会发生溢出,而不会自动提升为更高类型;同样,整数运算的结果仍然是整数 (例如,除法不会自动转换为浮点结果) 。因此,提前规划和设计值类型非常重要。在实际场景中,通常会使用浮点类型 (Float32/Float64) 。
  • 只有索引类型和值类型都相同的两个向量才能进行运算。
  • 底层存储采用 Bit-Sliced Index,索引由 bitmap 存储,具体实现使用的是 Roaring Bitmap。最佳实践是尽可能将索引集中到少数几个 Roaring Bitmap 容器中,以最大化压缩率和查询性能。
  • Bit-Sliced Index 机制会将值转换为二进制。对于浮点类型,转换时会使用定点表示,因此可能带来精度损失。精度可以通过自定义小数部分所使用的位数进行调整,默认值为 24 位,对大多数场景已足够。你可以在使用带 -State 的聚合函数 groupNumericIndexedVector 构造 NumericIndexedVector 时,自定义整数位数和小数位数。
  • 索引有三种情况:非零值、零值和不存在。在 NumericIndexedVector 中,只有非零值和零值会被存储。此外,在两个 NumericIndexedVector 之间进行按元素运算时,不存在的索引值会被视为 0。在除法场景下,如果除数为零,结果为零。

创建 numericIndexedVector 对象

创建这种结构有两种方式:一种是将聚合函数 groupNumericIndexedVector-State 结合使用。 你还可以添加 -if 后缀以接受额外条件。 该聚合函数只会处理满足该条件的行。 另一种方式是使用 numericIndexedVectorBuild 基于 map 构建。 groupNumericIndexedVectorState 函数允许通过参数自定义整数位和小数位的位数,而 numericIndexedVectorBuild 不支持。

groupNumericIndexedVector

从两个数据列构造 NumericIndexedVector,并以 Float64 类型返回所有值之和。若添加 State 后缀,则返回一个 NumericIndexedVector 对象。 语法
groupNumericIndexedVectorState(col1, col2)
groupNumericIndexedVectorState(type, integer_bit_num, fraction_bit_num)(col1, col2)
参数
  • type:String,可选。指定存储格式。目前仅支持 'BSI'
  • integer_bit_numUInt32,可选。仅在 'BSI' 存储格式下生效,表示整数部分使用的位数。当索引类型为整数类型时,默认值等于存储该索引所用的位数。例如,如果索引类型为 UInt16,则默认 integer_bit_num 为 16。对于 Float32 和 Float64 索引类型,integer_bit_num 的默认值为 40,因此可表示数据的整数部分范围为 [-2^39, 2^39 - 1]。其合法范围为 [0, 64]
  • fraction_bit_numUInt32,可选。仅在 'BSI' 存储格式下生效,表示小数部分使用的位数。当值类型为整数时,默认值为 0;当值类型为 Float32 或 Float64 时,默认值为 24。其合法范围为 [0, 24]
  • 此外还有一个约束:integer_bit_num + fraction_bit_num 的合法范围为 [0, 64]
  • col1:索引列。支持的类型:UInt8/UInt16/UInt32/Int8/Int16/Int32
  • col2:值列。支持的类型:Int8/Int16/Int32/Int64/UInt8/UInt16/UInt32/UInt64/Float32/Float64
返回值 一个 Float64 值,表示所有值之和。 示例 测试数据:
UserID  PlayTime
1       10
2       20
3       30
查询与结果:
SELECT groupNumericIndexedVector(UserID, PlayTime) AS num FROM t;
┌─num─┐
60
└─────┘

SELECT groupNumericIndexedVectorState(UserID, PlayTime) as res, toTypeName(res), numericIndexedVectorAllValueSum(res) FROM t;
┌─res─┬─toTypeName(res)─────────────────────────────────────────────┬─numericIndexedVectorAllValueSum(res)──┐
│     │ AggregateFunction(groupNumericIndexedVector, UInt8, UInt8)  │ 60
└─────┴─────────────────────────────────────────────────────────────┴───────────────────────────────────────┘

SELECT groupNumericIndexedVectorStateIf(UserID, PlayTime, day = '2025-04-22') as res, toTypeName(res), numericIndexedVectorAllValueSum(res) FROM t;
┌─res─┬─toTypeName(res)────────────────────────────────────────────┬─numericIndexedVectorAllValueSum(res)──┐
│     │ AggregateFunction(groupNumericIndexedVector, UInt8, UInt8) │ 30
└─────┴────────────────────────────────────────────────────────────┴───────────────────────────────────────┘

SELECT groupNumericIndexedVectorStateIf('BSI', 32, 0)(UserID, PlayTime, day = '2025-04-22') as res, toTypeName(res), numericIndexedVectorAllValueSum(res) FROM t;
┌─res─┬─toTypeName(res)──────────────────────────────────────────────────────────┬─numericIndexedVectorAllValueSum(res)──┐
│     │ AggregateFunction('BSI', 32, 0)(groupNumericIndexedVector, UInt8, UInt8) │ 30
└─────┴──────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────┘
下方文档由 system.functions 系统表自动生成。

numericIndexedVectorAllValueSum

在 v25.7.0 中引入 返回 numericIndexedVector 中所有值之和。 语法
numericIndexedVectorAllValueSum(v)
参数 返回值 返回其总和。Float64 示例 使用示例
Query
SELECT numericIndexedVectorAllValueSum(numericIndexedVectorBuild(mapFromArrays([1, 2, 3], [10, 20, 30]))) AS res;
Response
┌─res─┐
│  60 │
└─────┘

numericIndexedVectorBuild

引入版本:v25.7.0 从 Map 创建 NumericIndexedVector。Map 的键表示向量的索引,Map 的值表示向量的值。 语法
numericIndexedVectorBuild(map)
参数
  • map — 从索引到值的映射。Map
返回值 返回一个 NumericIndexedVector 对象。AggregateFunction 示例 使用示例
Query
SELECT numericIndexedVectorBuild(mapFromArrays([1, 2, 3], [10, 20, 30])) AS res, toTypeName(res);
Response
┌─res─┬─toTypeName(res)────────────────────────────────────────────┐
│     │ AggregateFunction(groupNumericIndexedVector, UInt8, UInt8) │
└─────┴────────────────────────────────────────────────────────────┘

numericIndexedVectorCardinality

引入版本:v25.7.0 返回 numericIndexedVector 的基数 (即唯一索引的数量) 。 语法
numericIndexedVectorCardinality(v)
参数 返回值 返回唯一索引的个数。UInt64 示例 使用示例
Query
SELECT numericIndexedVectorCardinality(numericIndexedVectorBuild(mapFromArrays([1, 2, 3], [10, 20, 30]))) AS res;
Response
┌─res─┐
│  3  │
└─────┘

numericIndexedVectorGetValue

引入版本:v25.7.0 从 numericIndexedVector 中获取与指定索引对应的值。 语法
numericIndexedVectorGetValue(v, i)
参数 返回值 一个数值,其类型与 NumericIndexedVector 中值的类型相同。(U)Int*Float* 示例 使用示例
Query
SELECT numericIndexedVectorGetValue(numericIndexedVectorBuild(mapFromArrays([1, 2, 3], [10, 20, 30])), 3) AS res;
Response
┌─res─┐
│  30 │
└─────┘

numericIndexedVectorPointwiseAdd

引入版本:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量进行按元素相加。 语法
numericIndexedVectorPointwiseAdd(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。numericIndexedVector 示例 用法示例
Query
WITH
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toInt32(x), [10, 20, 30]))) AS vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toInt32(x), [10, 20, 30]))) AS vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseAdd(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseAdd(vec1, 2)) AS res2;
Response
┌─res1──────────────────┬─res2─────────────┐
│ {1:10,2:30,3:50,4:30} │ {1:12,2:22,3:32} │
└───────────────────────┴──────────────────┘

numericIndexedVectorPointwiseDivide

引入版本:v25.7.0 对 numericIndexedVector 与另一个 numericIndexedVector 或数值常量执行按元素除法运算。 语法
numericIndexedVectorPointwiseDivide(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。numericIndexedVector 示例 使用示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 30]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [10, 20, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseDivide(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseDivide(vec1, 2)) AS res2;
Response
┌─res1────────┬─res2────────────┐
│ {2:2,3:1.5} │ {1:5,2:10,3:15} │
└─────────────┴─────────────────┘

numericIndexedVectorPointwiseEqual

引入版本:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量按元素进行比较。 结果是一个 numericIndexedVector,包含值相等的索引位置,且对应的所有值都设为 1。 语法
numericIndexedVectorPointwiseEqual(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。 示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 30]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [20, 20, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseEqual(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseEqual(vec1, 20)) AS res2;
Response
┌─res1──┬─res2──┐
│ {2:1} │ {2:1} │
└───────┴───────┘

numericIndexedVectorPointwiseGreater

引入于:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量按元素进行比较。 结果是一个 numericIndexedVector,其中包含第一个向量的值大于第二个向量值的索引,且所有对应的值均设为 1。 语法
numericIndexedVectorPointwiseGreater(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。numericIndexedVector 示例 使用示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 50]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [20, 40, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseGreater(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseGreater(vec1, 20)) AS res2;
Response
┌─res1──────┬─res2──┐
│ {1:1,3:1} │ {3:1} │
└───────────┴───────┘

numericIndexedVectorPointwiseGreaterEqual

引入版本:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量进行按元素比较。 结果是一个 numericIndexedVector,包含第一个向量中值大于或等于第二个向量对应值的索引,且所有对应值均设为 1。 语法
numericIndexedVectorPointwiseGreaterEqual(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。numericIndexedVector 示例 使用示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 50]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [20, 40, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseGreaterEqual(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseGreaterEqual(vec1, 20)) AS res2;
Response
┌─res1──────────┬─res2──────┐
│ {1:1,2:1,3:1} │ {2:1,3:1} │
└───────────────┴───────────┘

numericIndexedVectorPointwiseLess

引入版本:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量按元素进行比较。 结果为一个 numericIndexedVector,其中包含第一个向量的值小于第二个向量的值的索引,且所有对应的值都设为 1。 语法
numericIndexedVectorPointwiseLess(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。numericIndexedVector 示例 使用示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 30]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [20, 40, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseLess(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseLess(vec1, 20)) AS res2;
Response
┌─res1──────┬─res2──┐
│ {3:1,4:1} │ {1:1} │
└───────────┴───────┘

numericIndexedVectorPointwiseLessEqual

引入版本:v25.7.0 对 numericIndexedVector 与另一个 numericIndexedVector 或数值常量进行按元素比较。 结果为一个 numericIndexedVector,其中包含第一个向量中值小于或等于第二个向量对应值的位置索引,且所有对应值均设为 1。 语法
numericIndexedVectorPointwiseLessEqual(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。 示例 用法示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 30]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [20, 40, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseLessEqual(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseLessEqual(vec1, 20)) AS res2;
Response
┌─res1──────────┬─res2──────┐
│ {2:1,3:1,4:1} │ {1:1,2:1} │
└───────────────┴───────────┘

numericIndexedVectorPointwiseMultiply

引入版本:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量按元素执行乘法运算。 语法
numericIndexedVectorPointwiseMultiply(v1, v2)
参数 返回值 返回新的 numericIndexedVector 对象。numericIndexedVector 示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toInt32(x), [10, 20, 30]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toInt32(x), [10, 20, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseMultiply(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseMultiply(vec1, 2)) AS res2;
Response
┌─res1──────────┬─res2─────────────┐
│ {2:200,3:600} │ {1:20,2:40,3:60} │
└───────────────┴──────────────────┘

numericIndexedVectorPointwiseNotEqual

引入版本:v25.7.0 对一个 numericIndexedVector 与另一个 numericIndexedVector 或数值常量进行按元素比较。 结果是一个 numericIndexedVector,其中包含值不相等的位置索引,且所有对应的值均设为 1。 语法
numericIndexedVectorPointwiseNotEqual(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。numericIndexedVector 示例 使用示例
Query
with
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toFloat64(x), [10, 20, 30]))) as vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toFloat64(x), [20, 20, 30]))) as vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseNotEqual(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseNotEqual(vec1, 20)) AS res2;
Response
┌─res1──────────┬─res2──────┐
│ {1:1,3:1,4:1} │ {1:1,3:1} │
└───────────────┴───────────┘

numericIndexedVectorPointwiseSubtract

引入版本:v25.7.0 对 numericIndexedVector 与另一个 numericIndexedVector 或数值常量进行按元素相减。 语法
numericIndexedVectorPointwiseSubtract(v1, v2)
参数 返回值 返回一个新的 numericIndexedVector 对象。 示例 用法示例
Query
WITH
    numericIndexedVectorBuild(mapFromArrays([1, 2, 3], arrayMap(x -> toInt32(x), [10, 20, 30]))) AS vec1,
    numericIndexedVectorBuild(mapFromArrays([2, 3, 4], arrayMap(x -> toInt32(x), [10, 20, 30]))) AS vec2
SELECT
    numericIndexedVectorToMap(numericIndexedVectorPointwiseSubtract(vec1, vec2)) AS res1,
    numericIndexedVectorToMap(numericIndexedVectorPointwiseSubtract(vec1, 2)) AS res2;
Response
┌─res1───────────────────┬─res2────────────┐
│ {1:10,2:10,3:10,4:-30} │ {1:8,2:18,3:28} │
└────────────────────────┴─────────────────┘

numericIndexedVectorShortDebugString

自 v25.7.0 起引入 以 JSON 格式返回 numericIndexedVector 的内部信息。 此函数主要用于调试。 语法
numericIndexedVectorShortDebugString(v)
参数 返回值 返回包含调试信息的 JSON 字符串。String 示例 使用示例
Query
SELECT numericIndexedVectorShortDebugString(numericIndexedVectorBuild(mapFromArrays([1, 2, 3], [10, 20, 30]))) AS res\G;
Response
Row 1:
──────
res: {"vector_type":"BSI","index_type":"char8_t","value_type":"char8_t","integer_bit_num":8,"fraction_bit_num":0,"zero_indexes_info":{"cardinality":"0"},"non_zero_indexes_info":{"total_cardinality":"3","all_value_sum":60,"number_of_bitmaps":"8","bitmap_info":{"cardinality":{"0":"0","1":"2","2":"2","3":"2","4":"2","5":"0","6":"0","7":"0"}}}}

numericIndexedVectorToMap

引入版本:v25.7.0 将 numericIndexedVector 转换为映射 (Map) 。 语法
numericIndexedVectorToMap(v)
参数 返回值 返回包含索引和值对的映射。Map 示例 使用示例
Query
SELECT numericIndexedVectorToMap(numericIndexedVectorBuild(mapFromArrays([1, 2, 3], [10, 20, 30]))) AS res;
Response
┌─res──────────────┐
│ {1:10,2:20,3:30} │
└──────────────────┘
最后修改于 2026年6月10日