ClickHouse社区提供了 bitmap 数据处理能力,详见Bitmap Functions | ClickHouse Docs ,在差不多同期,ByteHouse 也自研了一套处理 bitmap 数据的类型和相关函数,两者在数据存储和使用方法上存在一定异同,更多关于BitMap类型数据的对比介绍请参见BitMap64类型文档。
ByteHouse为您提供了丰富的函数接口便于您查询BitMap64类型的数据,可大致分为普通函数、聚合函数、高阶聚合函数等类型,以下为您介绍ByteHouse的BitMap函数的接口list和使用说明。
ByteHouse的BitMap普通函数接收一行记录或者一个BitMap64对象,返回一行结果。
这部分的函数接口,除第一个函数arrayToBitmap外,其它的均和社区函数接口保持一致。
序号 | 函数接口 | 参数说明 | 返回值 | 功能释义 |
|---|---|---|---|---|
1 | arrayToBitmap([x1, …]) | UIntN类型的数组 | BitMap64对象 | 通过一个数组构造一个bitmap对象 |
2 | bitmapToArray(bitmap) | 一个BitMap64对象 | UInt64数组 | 将一个bimap对象转换为数组格式 |
3 | bitmapAnd(bitmap1, bitmap2) | 两个BitMap64对象 | BitMap64对象 | bitmap的交运算 |
4 | bitmapOr(bitmap1, bitmap2) | 两个BitMap64对象 | BitMap64对象 | bitmap的并运算 |
5 | bitmapXor(bitmap1, bitmap2) | 两个BitMap64对象 | BitMap64对象 | bitmap的异或运算 |
6 | bitmapAndnot(bitmap1, bitmap2) | 两个BitMap64对象 | BitMap64对象 | bitmap的差运算 |
7 | bitmapCardinality(bitmap) | 一个BitMap64对象 | UInt64数值 | bitmap中元素的个数 |
8 | bitmapMin(bitmap) | 一个BitMap64对象 | UInt64数值 | bitmap中最小的元素 |
9 | bitmapMax(bitmap) | 一个BitMap64对象 | UInt64数值 | bitmap中最大的元素 |
10 | bitmapAndCardinality | 两个BitMap64对象 | UInt64数值 | bitmap的交运算之后的元素个数 |
11 | bitmapOrCardinality | 两个BitMap64对象 | UInt64数值 | bitmap的并运算之后的元素个数 |
12 | bitmapXorCardinality | 两个BitMap64对象 | UInt64数值 | bitmap的异或运算之后的元素个数 |
13 | bitmapAndnotCardinality | 两个BitMap64对象 | UInt64数值 | bitmap的差运算之后的元素个数 |
14 | bitmapContains(bitmap, integer) | 一个BitMap64对象 | UInt8枚举 | 检查bitmap中是否包含指定元素 |
15 | bitmapHasAll | 两个BitMap64对象 | UInt8枚举 | 检查sub_bitmap是否是bitmap的子集 |
16 | bitmapHasAny | 两个BitMap64对象 | UInt8枚举 | 检查两个bitmap是否存在交集 |
17 | bitmapSubsetInRange | 一个BitMap64对象,两个UIntN数字,标识取值范围 | BitMap64对象 | 检查并返回bitmap中符合给定元素大小范围的值组成的bitmap。 |
18 | bitmapSubsetLimit | 一个BitMap64对象,两个UIntN数字,标识下标启示范围,和子集大小 | BitMap64对象 | 检查并返回由bitmap中指定元素开始的,不超过指定数量的元素组成的bitmap。 |
19 | subBitmap(bitmap, start_offset, length) | 一个BitMap64对象, | BitMap64对象 | 提取bitmap中指定下标范围的数据,类比subString。 |
将两个位图进行相加计算,结果是一个新的位图。
语法
bitmapAnd(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
示例
SELECT bitmapToArray(bitmapAnd(bitmapBuild([1,2,3]),bitmapBuild([3,4,5]))) AS res;
结果:
┌─res─┐ │ [3] │ └─────┘
两个位图的和计算,返回 UInt64 类型的基数。
语法
bitmapAndCardinality(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
UInt64。类型:Uint64
示例
SELECT bitmapAndCardinality(bitmapBuild([1,2,3]),bitmapBuild([3,4,5])) AS res;
结果:
┌─res─┐ │ 1 │ └─────┘
两个位图的和不进行计算,结果是一个新的位图。
语法
bitmapAndnot(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
类型:Bitmap object。
示例
SELECT bitmapToArray(bitmapAndnot(bitmapBuild([1,2,3]),bitmapBuild([3,4,5]))) AS res;
结果:
┌─res────┐ │ [1, 2] │ └────────┘ 纯文本
两个位图的与不计算,返回 UInt64 类型的基数。
语法
bitmapAndnotCardinality(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
UInt64。类型:UInt64
示例
SELECT bitmapAndnotCardinality(bitmapBuild([1,2,3]),bitmapBuild([3,4,5])) AS res;
结果:
┌─res─┐ │ 2 │ └─────┘
从无符号整数数组构建位图。
语法
bitmapBuild(array)
参数
array– 无符号整数数组。返回值
类型:Bitmap object。
示例
SELECT toTypeName(bitmapBuild([1, 2, 3, 4, 5]));
结果:
┌─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─┐ │ AggregateFunction(groupBitmap, UInt8) │ └──────────────────────────────────────────┘
返回 UInt64 类型的位图基数。
语法
bitmapCardinality(bitmap)
参数
bitmap– 位图对象。返回值
UInt64。类型:UInt64。
示例
SELECT bitmapCardinality(bitmapBuild([1, 2, 3, 4, 5])) AS res;
结果:
┌─res─┐ │ 5 │ └─────┘
检查位图是否包含元素。
语法
bitmapContains(haystack, needle)
参数
haystack– [位图对象],函数在其中搜索。needle– 函数搜索的值。类型:[UInt32]。返回值
haystack不包含needle。haystack包含needle。类型:UInt8。
示例
SELECT bitmapContains(bitmapBuild([1,5,7,9]), toUInt32(9)) AS res;
结果:
┌─res─┐ │ 1 │ └─────┘
hasAll(array, array)如果第一个位图包含第二个位图的所有元素,则类似于返回 1,否则返回 0。
如果第二个参数是空位图,则返回 1。
语法
bitmapHasAll(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
1,如果第一个位图包含第二个位图的所有元素或第二个参数为空位图,则返回 1。0, 否则。类型:UInt8
示例
SELECT bitmapHasAll(bitmapBuild([1,2,3]),bitmapBuild([3,4,5])) AS res;
结果:
┌─res─┐ │ 0 │ └─────┘
检查两个位图是否有某些元素的交集。
语法
bitmapHasAny(bitmap1, bitmap2)
如果您确定bitmap2只包含一个元素,请考虑使用 [bitmapContains] 函数。它工作得更有效率。
参数
bitmap*– 位图对象。返回值
1,若bitmap1和bitmap2至少有一个相似元素。0, 否则。示例
SELECT bitmapHasAny(bitmapBuild([1,2,3]),bitmapBuild([3,4,5])) AS res;
结果:
┌─res─┐ │ 1 │ └─────┘
返回集合中 UInt64 类型的最大值,如果集合为空则返回 0。
语法
bitmapMax(bitmap)
参数
bitmap– 位图对象。返回值
类型:UInt64
示例
SELECT bitmapMax(bitmapBuild([1, 2, 3, 4, 5])) AS res;
结果:
┌─res─┐ │ 5 │ └─────┘
返回集合中 UInt64 类型的最小值,如果集合为空,则返回 UINT32_MAX。
语法
bitmapMin(bitmap)
参数
bitmap– 位图对象。返回值
类型:UInt64
示例
SELECT bitmapMin(bitmapBuild([1, 2, 3, 4, 5])) AS res;
结果:
┌─res─┐ │ 1 │ └─────┘
两个位图进行或计算,结果是一个新的位图。
bitmapOr(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
类型:Bitmap object。
示例
SELECT bitmapToArray(bitmapOr(bitmapBuild([1,2,3]),bitmapBuild([3,4,5]))) AS res;
结果:
┌─res─────────────┐ │ [1, 2, 3, 4, 5] │ └─────────────────┘
两个位图或计算,返回 UInt64 类型的基数。
语法
bitmapOrCardinality(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
类型:UInt64
示例
SELECT bitmapOrCardinality(bitmapBuild([1,2,3]),bitmapBuild([3,4,5])) AS res;
结果:
┌─res─┐ │ 5 │ └─────┘
返回指定范围内的子集(不包括range_end)。
语法
bitmapSubsetInRange(bitmap, range_start, range_end)
参数
bitmap– [位图对象]。range_start– 范围起点。类型:[UInt32]。range_end– 范围终点(排除)。类型:[UInt32]。返回值
类型:array
示例
SELECT bitmapToArray(bitmapSubsetInRange(bitmapBuild([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,100,200,500]), toUInt32(30), toUInt32(200))) AS res;
结果:
┌─res───────────────────┐ │ [30, 31, 32, 33, 100] │ └───────────────────────┘
创建位图的子集,其中包含range_start和之间的 n 个元素cardinality_limit。
语法
bitmapSubsetLimit(bitmap, range_start, cardinality_limit)
参数
bitmap– [位图对象]。range_start– 子集的起点。类型:[UInt32]。cardinality_limit– 子集基数上限。类型:[UInt32]。返回值
类型:Bitmap object。
示例
SELECT bitmapToArray(bitmapSubsetLimit(bitmapBuild([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,100,200,500]), toUInt32(30), toUInt32(200))) AS res;
结果:
┌─res─────────────────────────────┐ │ [30, 31, 32, 33, 100, 200, 500] │ └─────────────────────────────────┘
将位图转换为整数数组。
语法
bitmapToArray(bitmap)
参数
bitmap– 位图对象。返回值
类型:array。
示例
SELECT bitmapToArray(bitmapBuild([1, 2, 3, 4, 5])) AS res;
结果:
┌─res─────────────┐ │ [1, 2, 3, 4, 5] │ └─────────────────┘
两个位图进行异或计算,结果是一个新的位图。
bitmapXor(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
类型:Bitmap object。
示例
SELECT bitmapToArray(bitmapXor(bitmapBuild([1,2,3]),bitmapBuild([3,4,5]))) AS res;
结果:
┌─res──────────┐ │ [1, 2, 4, 5] │ └──────────────┘
两个位图进行异或计算,返回 UInt64 类型的基数。
语法
bitmapXorCardinality(bitmap,bitmap)
参数
bitmap– 位图对象。返回值
类型:Bitmap object。
示例
SELECT bitmapXorCardinality(bitmapBuild([1,2,3]),bitmapBuild([3,4,5])) AS res;
结果:
┌─res─┐ │ 4 │ └─────┘
提取bitmap中指定下标范围的子集数据,从offset位置开始。返回的位图的最大基数是cardinality_limit。
语法
subBitmap(bitmap, offset, cardinality_limit)
参数
bitmap - [位图对象]offset - 子集中第一个元素的位置,UInt32 类型cardinality_limit - 子集最大基数,UInt32 类型需要注意,offset从0开始,代表实际存储的第一个有效值,类似于数组下标。offset和 cardinality_limit 超过 bitmap 元素个数均无意义。
返回值
示例
SELECT bitmapToArray(subBitmap(bitmapBuild([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,100,200,500]), toUInt32(10), toUInt32(10))) AS res; --- 等价于 ByteHouse BitMap64类型如下写法 SELECT bitmapToArray(subBitmap(arrayToBitmap([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 100, 200, 500]), toUInt32(10), toUInt32(10))) AS res
┌─res─────────────────────────────┐ │ [10,11,12,13,14,15,16,17,18,19] │ └─────────────────────────────────┘
下述聚合函数接收多行记录,进行聚合操作,返回一行结果。
序号 | 函数接口 | 参数说明 | 返回值 | 功能释义 |
|---|---|---|---|---|
1 | bitmapColumnAnd | BitMap64类型的一列数据 | BitMap64对象 | 接收一个bimap列,该列所有bitmap做交运算 |
2 | bitmapColumnOr | BitMap64类型的一列数据 | BitMap64对象 | 接收一个bimap列,该列所有bitmap做并运算 |
3 | bitmapColumnXor | BitMap64类型的一列数据 | BitMap64对象 | 接收一个bimap列,该列所有bitmap做异或运算 |
4 | bitmapColumnCardinality | BitMap64类型的一列数据 | UInt64数值 | 接收一个bimap列,该列所有bitmap做并运算,返回最终结果bitmap的元素个数 |
5 | bitmapColumnHas | BitMap64类型的一列数据 | UInt8枚举 | 接收一个bimap列,检查该列是否包含指定元素 |
6 | bitmapFromColumn(id) -> bitmap | 整数列 | BitMap64对象 | 接收一列整数,聚合成一个bitmap |
以下是具体的函数示例:
计算一列 bitmap 的交集。
语法
bitmapColumnAnd(bitmap_column)
参数bitmap_column - BitMap64 类型的数据列。
返回值
示例
select bitmapColumnAnd(rbm) as result from ( select arrayToBitmap([1,2,3]) as rbm union all select arrayToBitmap([2,3,4]) as rbm )
结果:
┌─result─┐ │ {2,3} │ └────────┘
计算一列 bitmap 的并集。
语法
bitmapColumnOr(bitmap_column)
参数bitmap_column - BitMap64 类型的数据列。
返回值
示例
select bitmapColumnOr(rbm) as result from ( select arrayToBitmap([1,2,3]) as rbm union all select arrayToBitmap([2,3,4]) as rbm )
结果:
┌─result────┐ │ {1,2,3,4} │ └───────────┘
计算一列 bitmap 的异或集。
语法
bitmapColumnXor(bitmap_column)
参数bitmap_column - BitMap64 类型的数据列。
返回值
示例
select bitmapColumnXor(rbm) as result from ( select arrayToBitmap([1,2,3]) as rbm union all select arrayToBitmap([2,3,4]) as rbm )
结果:
┌─result─┐ │ {1,4} │ └────────┘
计算一列 bitmap 的并集包含的元素个数。
语法
bitmapColumnCardinality(bitmap_column)
参数bitmap_column - BitMap64 类型的数据列。
返回值
示例
select bitmapColumnCardinality(rbm) as result from ( select arrayToBitmap([1,2,3]) as rbm union all select arrayToBitmap([2,3,4]) as rbm )
结果:
┌─result─┐ │ 4 │ └────────┘
判断一列 bitmap 中是否包含指定数值。
语法
bitmapColumnHas(bitmap_column, integer_number)
参数bitmap_column - BitMap64 类型的数据列。integer_number - 一个常量数值。类型为64位以内的正整数。
返回值
bitmapContains的区别在于改函数对于一列 bitmap仅返回一行值,bitmapContains则是多行。示例
select bitmapColumnHas(rbm, 3) as result from ( select arrayToBitmap([1,2,3]) as rbm union all select arrayToBitmap([2,3,4]) as rbm )
结果:
┌─result─┐ │ 1 │ └────────┘
从一列数值中构建一个BitMap64 对象。
语法
bitmapFromColumn(integer_column)
参数
integer_column - 64 位以内的正整数列。返回值
示例
select bitmapFromColumn(number) as res from numbers(10);
结果:
┌─res───────────────────┐ │ {0,1,2,3,4,5,6,7,8,9} │ └───────────────────────┘
这种函数有两个括号传递参数:
ByteHouse 提供了一系列聚合函数用于批量处理大量 bitmap 之间的复杂计算。通过给每个待计算的 bitmap编序号,并用序号书写表达出集合的交并差运算,ByteHouse 可以根据指定的运算表达式完成对应的 bitmap 运算,直接把计算可视化和简便化,极大提升了写 SQL的体验!
简单图示如下:
序号 | 函数接口 | 参数说明 | 返回值 | 功能释义 |
|---|---|---|---|---|
1 | bitmapCount | expression是与或差表达式, | UInt64数值 | 对于bitmap列中的每一行,取其标记idx,存入 map 中。最终依据expression指定的计算方式进行bitmap运算,返回最终bitmap中元素个数 |
2 | bitmapExtract | expression是与或差表达式, | BitMap64对象 | 对于bitmap列中的每一行,取其idx,并依据expression指定的计算方式进行bitmap运算,返回最终计算结果的bitmap |
3 | bitmapMultiCount | expression是与或差表达式, | UInt64数组 | 对于bitmap列中的每一行,取其编号 idx,并依据每个expr指定的计算方式进行多组bitmap运算,返回每组expr计算的结果bitmap中元素个数 |
4 | bitmapMultiExtract | expression是与或差表达式, | BitMap64数组 | 对于bitmap列中的每一行,取其编号 idx,并依据每个expr指定的计算方式进行多组bitmap运算,返回每组expr计算的结果的bitmap数据 |
5 | bitmapMultiCountWithDate | expression是与或差表达式, | UInt64数组 | 在bitmapMultiCount的基础上增加了日期维度,可以区别出不同日期中的编号。即 bitmapMultiCount 只支持一个编号维度,该函数则额外增加了日期维度。 |
6 | bitmapMultiExtractWithDate | expression是与或差表达式, | BitMap64数组 | 在bitmapMultiExtract的基础上增加了日期维度,可以区别出不同日期中的标签。即 bitmapMultiExtract 只支持一个编号维度,该函数则额外增加了日期维度。 |
说明
如果存在相同编号idx的多行数据,聚合函数会自动把多行bitmap通过OR运算合并为一个,参与计算。最终计算时,一个idx对应一个bitmap。
以下是具体的函数说明。
依据用户指定的计算表达式,执行相应的bitmap运算,返回最终bitmap中元素个数。
语法
BitMapCount(expr)(idx_column, bitmap_column)
参数
expr - 使用数字或字符串表示的与(&)、或(|)、差(~)运算,&表示bitmap交集,|表示bitmap并集,~表示bitmap差集,该函数仅支持一个表达式。idx_column - 用于标记 bitmap的数据列,可以是整数列(通常为 Int16/32/64类型),或者字符串列。bitmap_column - BitMap64 数据列。注1:不要求idx_column数据和bitmap_column数据一一对应,如果idx_column存在重复数据,则值相同的多行 bitmap 会先进行并集运算,合并为一个唯一的 bitmap 参与计算。
注 2:当idx_column列类型位字符串时,不能包含如下保留字符:&, |, ~, ,, #, (, ), _和英文空格。
返回值
示例
SELECT bitmapCount('a')(tag_value, uids) AS res FROM ( SELECT 'a' AS tag_value, arrayToBitmap([1, 2, 3]) AS uids )
结果:
┌─res─┐ │ 3 │ └─────┘
SELECT BitmapCount('((a&b)|c) ~ d')(tag_value, uids) AS res1, BitmapCount('((1&2)|3)~4')(multiIf(tag_value = 'a', toInt16(1), tag_value = 'b', toInt16(2), tag_value = 'c', toInt16(3), tag_value = 'd', toInt16(4), toInt16(0)) AS idx, uids) AS res2 FROM ( SELECT 'a' AS tag_value, arrayToBitmap([1, 2, 3, 4, 5]) AS uids UNION ALL SELECT 'b' AS tag_value, arrayToBitmap([3, 4, 5, 6]) AS uids UNION ALL SELECT 'c' AS tag_value, arrayToBitmap([5, 7]) AS uids UNION ALL SELECT 'd' AS tag_value, arrayToBitmap([7]) AS uids )
结果
┌─res1─┬─res2─┐ │ 3 │ 3 │ └──────┴──────┘
依据用户指定的计算表达式,执行相应的bitmap运算,返回最终bitmap。
语法
BitMapExtract(expr)(idx_column, bitmap_column)
参数
expr - 使用数字或字符串表示的与(&)、或(|)、差(~)运算,&表示bitmap交集,|表示bitmap并集,~表示bitmap差集,该函数仅支持一个表达式。idx_column - 用于标记 bitmap的数据列,可以是整数列(通常为 Int16/32/64类型),或者字符串列。bitmap_column - BitMap64 数据列。注意
idx_column数据和bitmap_column数据一一对应,如果idx_column存在重复数据,则值相同的多行 bitmap 会先进行并集运算,合并为一个唯一的 bitmap 参与计算。idx_column列类型位字符串时,不能包含如下保留字符:&, |, ~, ,, #, (, ), _和英文空格。返回值
示例
SELECT bitmapExtract('a')(tag_value, uids) AS res FROM ( SELECT 'a' AS tag_value, arrayToBitmap([1, 2, 3]) AS uids )
结果
┌─res─────┐ │ {1,2,3} │ └─────────┘
SELECT BitmapExtract('((a&b)|c) ~ d')(tag_value, uids) AS res1, BitmapExtract('((1&2)|3)~4')(multiIf(tag_value = 'a', toInt16(1), tag_value = 'b', toInt16(2), tag_value = 'c', toInt16(3), tag_value = 'd', toInt16(4), toInt16(0)) AS idx, uids) AS res2 FROM ( SELECT 'a' AS tag_value, arrayToBitmap([1, 2, 3, 4, 5]) AS uids UNION ALL SELECT 'b' AS tag_value, arrayToBitmap([3, 4, 5, 6]) AS uids UNION ALL SELECT 'c' AS tag_value, arrayToBitmap([5, 7]) AS uids UNION ALL SELECT 'd' AS tag_value, arrayToBitmap([7]) AS uids )
结果:
┌─res1────┬─res2────┐ │ {3,4,5} │ {3,4,5} │ └─────────┴─────────┘
依据用户指定的一组计算表达式,每组执行相应的bitmap运算,返回每组最终bitmap中元素个数。
语法
BitmapMultiCount(expr1, expr2, expr3,...)(idx_column, bitmap_column)
参数
expr - 使用数字或字符串表示的与(&)、或(|)、差(~)运算,&表示bitmap交集,|表示bitmap并集,~表示bitmap差集,该函数支持多个表达式。idx_column - 用于标记 bitmap的数据列,可以是整数列(通常为 Int16/32/64类型),或者字符串列。bitmap_column - BitMap64 数据列。注意
idx_column数据和bitmap_column数据一一对应,如果idx_column存在重复数据,则值相同的多行 bitmap 会先进行并集运算,合并为一个唯一的 bitmap 参与计算。idx_column列类型位字符串时,不能包含如下保留字符:&, |, ~, ,, #, (, ), _和英文空格。expr1='a&b', expr2='(a&b)|c。那么可以简化 expr2 的写法为expr2='_1|c'。使用下划线+数字可以指定某个已经出现过的表达式,可以简化复杂表达式写法。返回值
示例
SELECT BitmapMultiCount('a')(tag_value, uids) AS res FROM ( SELECT 'a' AS tag_value, arrayToBitmap([1, 2, 3]) AS uids )
┌─res─┐ │ [3] │ └─────┘
SELECT BitmapMultiCount('1&2', '(1&2)|3', '_1|3', '((1&2)|3) ~ 4', '_2~4')(tag_value, uids) AS res FROM ( SELECT toInt32(1) AS tag_value, arrayToBitmap([1, 2, 3, 4, 5]) AS uids UNION ALL SELECT toInt32(2) AS tag_value, arrayToBitmap([3, 4, 5, 6]) AS uids UNION ALL SELECT toInt32(3) AS tag_value, arrayToBitmap([5, 7]) AS uids UNION ALL SELECT toInt32(4) AS tag_value, arrayToBitmap([7]) AS uids )
结果:
┌─res─────────┐ │ [3,4,4,3,3] │ └─────────────┘
依据用户指定的一组计算表达式,每组执行相应的bitmap运算,返回每组最终bitmap。
语法
BitmapMultiExtract(expr1, expr2, expr3,...)(idx_column, bitmap_column)
参数
expr - 使用数字或字符串表示的与(&)、或(|)、差(~)运算,&表示bitmap交集,|表示bitmap并集,~表示bitmap差集,该函数支持多个表达式。idx_column - 用于标记 bitmap的数据列,可以是整数列(通常为 Int16/32/64类型),或者字符串列。bitmap_column - BitMap64 数据列。注意
idx_column数据和bitmap_column数据一一对应,如果idx_column存在重复数据,则值相同的多行 bitmap 会先进行并集运算,合并为一个唯一的 bitmap 参与计算。idx_column列类型位字符串时,不能包含如下保留字符:&, |, ~, ,, #, (, ), _和英文空格。expr1='a&b', expr2='(a&b)|c。那么可以简化 expr2 的写法为expr2='_1|c'。使用下划线+数字可以指定某个已经出现过的表达式,可以简化复杂表达式写法。返回值
示例
SELECT BitmapMultiExtract('a')(tag_value, uids) AS res FROM ( SELECT 'a' AS tag_value, arrayToBitmap([1, 2, 3]) AS uids )
┌─res───────┐ │ [{1,2,3}] │ └───────────┘
SELECT BitmapMultiExtract('1&2', '(1&2)|3', '_1|3', '((1&2)|3) ~ 4', '_2~4')(tag_value, uids) AS res FROM ( SELECT toInt32(1) AS tag_value, arrayToBitmap([1, 2, 3, 4, 5]) AS uids UNION ALL SELECT toInt32(2) AS tag_value, arrayToBitmap([3, 4, 5, 6]) AS uids UNION ALL SELECT toInt32(3) AS tag_value, arrayToBitmap([5, 7]) AS uids UNION ALL SELECT toInt32(4) AS tag_value, arrayToBitmap([7]) AS uids )
结果:
┌─res───────────────────────────────────────────┐ │ [{3,4,5},{3,4,5,7},{3,4,5,7},{3,4,5},{3,4,5}] │ └───────────────────────────────────────────────┘
依据用户指定的一组计算表达式,每组执行相应的bitmap运算,返回每组最终bitmap中元素个数。相比函数BitmapMultiCount多了一个日期表示维度。
语法
BitmapMultiCountWithDate(expr1, expr2, expr3,...)(date_column, idx_column, bitmap_column)
参数
expr - 使用数字或字符串表示的与(&)、或(|)、差(~)运算,&表示bitmap交集,|表示bitmap并集,~表示bitmap差集,该函数支持多个表达式,需要注意每个表达式由两部分组成:一部分是日期,一部分是标记,并使用下划线连接,示例为20240101_aaa&20240102_aaa。date_colulmn - 用于指定数据日期,需要时 Int64 类型表示的日期列,格式为 YYYYMMDD。idx_column - 用于标记 bitmap的数据列,可以是整数列(通常为 Int16/32/64类型),或者字符串列。bitmap_column - BitMap64 数据列。注意
date_column+idx_column数据和bitmap_column数据一一对应,如果date_column+idx_column存在重复数据,则值相同的多行 bitmap 会先进行并集运算,合并为一个唯一的 bitmap 参与计算。idx_column列类型位字符串时,不能包含如下保留字符:&, |, ~, ,, #, (, ), _和英文空格。expr1='a&b', expr2='(a&b)|c。那么可以简化 expr2 的写法为expr2='_1|c'。使用下划线+数字可以指定某个已经出现过的表达式,可以简化复杂表达式写法。返回值
示例
SELECT BitmapMultiCountWithDate('20240102_a~20240101_a', '20240101_a&20240102_a')(toInt64(toYYYYMMDD(date)), tag_value, uids) AS res FROM ( SELECT 'a' AS tag_value, '2024-01-01' AS date, arrayToBitmap([1, 2, 3]) AS uids UNION ALL SELECT 'a' AS tag_value, '2024-01-02' AS date, arrayToBitmap([2, 3, 4, 5, 6]) AS uids )
┌─res───┐ │ [3,2] │ └───────┘
SELECT BitmapMultiCountWithDate('20240101_1 & 20240102_2', '_1 | 20240101_3', '_2 ~ 20240101_4')(toInt64(toYYYYMMDD(date)), tag_value, uids) AS res FROM ( SELECT toInt32(1) AS tag_value, '2024-01-01' AS date, arrayToBitmap([1, 2, 3, 4, 5]) AS uids UNION ALL SELECT toInt32(2) AS tag_value, '2024-01-02' AS date, arrayToBitmap([3, 4, 5, 6]) AS uids UNION ALL SELECT toInt32(3) AS tag_value, '2024-01-01' AS date, arrayToBitmap([5, 7]) AS uids UNION ALL SELECT toInt32(4) AS tag_value, '2024-01-01' AS date, arrayToBitmap([7]) AS uids )
结果:
┌─res─────┐ │ [3,4,3] │ └─────────┘
依据用户指定的一组计算表达式,每组执行相应的bitmap运算,返回每组最终bitmap。相比函数BitmapMultiExtract多了一个日期表示维度。
语法
BitmapMultiExtractWithDate(expr1, expr2, expr3,...)(date_column, idx_column, bitmap_column)
参数
expr - 使用数字或字符串表示的与(&)、或(|)、差(~)运算,&表示bitmap交集,|表示bitmap并集,~表示bitmap差集,该函数支持多个表达式,需要注意每个表达式由两部分组成:一部分是日期,一部分是标记,并使用下划线连接,示例为20240101_aaa&20240102_aaa。date_colulmn - 用于指定数据日期,需要时 Int64 类型表示的日期列,格式为 YYYYMMDD。idx_column - 用于标记 bitmap的数据列,可以是整数列(通常为 Int16/32/64类型),或者字符串列。bitmap_column - BitMap64 数据列。注意
date_column+idx_column数据和bitmap_column数据一一对应,如果date_column+idx_column存在重复数据,则值相同的多行 bitmap 会先进行并集运算,合并为一个唯一的 bitmap 参与计算。idx_column列类型位字符串时,不能包含如下保留字符:&, |, ~, ,, #, (, ), _和英文空格。expr1='a&b', expr2='(a&b)|c。那么可以简化 expr2 的写法为expr2='_1|c'。使用下划线+数字可以指定某个已经出现过的表达式,可以简化复杂表达式写法。返回值
示例
SELECT BitmapMultiExtractWithDate('20240102_a~20240101_a', '20240101_a&20240102_a')(toInt64(toYYYYMMDD(date)), tag_value, uids) AS res FROM ( SELECT 'a' AS tag_value, '2024-01-01' AS date, arrayToBitmap([1, 2, 3]) AS uids UNION ALL SELECT 'a' AS tag_value, '2024-01-02' AS date, arrayToBitmap([2, 3, 4, 5, 6]) AS uids )
┌─res─────────────┐ │ [{4,5,6},{2,3}] │ └─────────────────┘
SELECT BitmapMultiExtractWithDate('20240101_1 & 20240102_2', '_1 | 20240101_3', '_2 ~ 20240101_4')(toInt64(toYYYYMMDD(date)), tag_value, uids) AS res FROM ( SELECT toInt32(1) AS tag_value, '2024-01-01' AS date, arrayToBitmap([1, 2, 3, 4, 5]) AS uids UNION ALL SELECT toInt32(2) AS tag_value, '2024-01-02' AS date, arrayToBitmap([3, 4, 5, 6]) AS uids UNION ALL SELECT toInt32(3) AS tag_value, '2024-01-01' AS date, arrayToBitmap([5, 7]) AS uids UNION ALL SELECT toInt32(4) AS tag_value, '2024-01-01' AS date, arrayToBitmap([7]) AS uids )
结果:
┌─res─────────────────────────┐ │ [{3,4,5},{3,4,5,7},{3,4,5}] │ └─────────────────────────────┘
No. | Function interface | Parameter description | Return value | Brief explanation |
|---|---|---|---|---|
1 | EncodeNonBitEngineColumn(UInt64_column, database, table, dictionary,add_new_key_to_bitengine_dict) | UInt64_column: | UInt64 value | 用普通的UInt64作为 BitEngine K-V dictionary中的K,以获取该值经过字典编码之后的值 |
2 | DecodeNonBitEngineColumn(UInt64_column, database, table, dictionary) | UInt64_column: | UInt64 value | 用普通的UInt64作为 BitEngine K-V dictionary中的V,以获取该值在字典编码之前的值 |
3 | EncodeBitmap(bitmap, database, table, dictionary, add_new_key_to_bitengine_dict) | bitmap: source input; | BitMap64 object | 使用BitEngine dictionary来对一个bitmap做编码操作 |
4 | DecodeBitmap(bitmap, database, table, dictionary) | bitmap: source input; | BitMap64 object | 使用BitEngine dictionary来对一个bitmap做解码操作 |
5 | arrayToBitmapWithEncode 最后一个参数是新增的可选参数。没有就是默认值0,如果需要则必须带上,且赋值为1 | UIntN类型的数组, | BitMap64对象 | 利用已存在的BitEngine字典给新的bitmap编码,返回编码后的bitmap |
6 | bitmapToArrayWithDecode(bitmap, 'db', 'tbl', 'dict_name') | bitmap: source input; | Array(UInt64) | 解码bitmap,同时将bitmap转为数组 |
如果您此前使用了社区的BitMap函数,当前希望迁移至ByteHouse,可参考如下规则替换社区的BitMap函数。
注意
ClickHouse/ByteHouse 是支持聚合函数组合算子,详见Aggregate Function Combinators,其使用格式是【聚合函数名】+【Combinator】,常见的 Combinator 如 -If,-State。如groupBitmapOrState、groupBitmapOrStateIf,替换函数时,只需要考虑groupBitmapOr函数名就行,Combinator 部分不变。
常见 Combinator 的替换规则:
-State:直接去掉-If :保留-Merge:直接去掉示例:groupBitmapStateIf -> bitmapFromColumnIfgroupBitmapOrState -> bitmapColumnOr
ByteHouse 适配以及支持了所有 ClickHouse 社区的 bitmap 函数,其映射关系如下:
ClickHouse 社区函数名 | ByteHouse 对等实现 | 示例 |
|---|---|---|
bitmapBuild | arrayToBitmap | 示例: |
bitmapToArray | bitmapToArray | 示例: |
bitmapSubsetInRange | bitmapSubsetInRange | 示例: |
bitmapSubsetLimit | bitmapSubsetLimit | 示例: |
subBitmap | subBitmap | 示例: |
bitmapContains | bitmapContains | 示例: |
bitmapHasAny | bitmapHasAny | 示例: |
bitmapHasAll | bitmapHasAll | 示例: |
bitmapCardinality | bitmapCardinality | 示例: |
bitmapMin | bitmapMin | 示例: |
bitmapMax | bitmapMax | 示例: |
bitmapTransform | bitmapTransform | 示例: |
bitmapAnd | bitmapAnd | 示例: |
bitmapOr | bitmapOr | 示例: |
bitmapXor | bitmapXor | 示例: |
bitmapAndnot | bitmapAndnot | 示例: |
bitmapAndCardinality | bitmapAndCardinality | 示例: |
bitmapOrCardinality | bitmapOrCardinality | 示例: |
bitmapXorCardinality | bitmapXorCardinality | 示例: |
bitmapAndnotCardinality | bitmapAndnotCardinality | 示例: |
groupBitmap | bitmapCardinality(bitmapFromColumn(number)) | 示例: |
groupBitmapState | bitmapFromColumn | 示例: |
groupBitmapOr | bitmapColumnCardinality | 示例: |
groupBitmapOrState | bitmapColumnOr | 示例: |
groupBitmapAnd | bitmapCardinality(bitmapColumnAnd(bitmap_column)) | 示例: |
groupBitmapAndState | bitmapColumnAnd | 示例: |
groupBitmapXor | bitmapCardinality(bitmapColumnXor(bitmap_column)) | 示例: |
groupBitmapXorState | bitmapColumnXor | 示例: |
示例用表 test.bitmap_test。
CREATE TABLE test.bitmap_test ( `p_date` Date, `slice_id` UInt64, `tag_id` Int32, `tag_value` String, `uids` BitMap64 ) ENGINE = CnchMergeTree PARTITION BY p_date ORDER BY (tag_id, tag_value) SETTINGS index_granularity = 128;
数据涉及两个标签,tag_id=11,有两个标签值'a'和'b';tag_id=12,有一个标签值'c'。
每个标签值有两行,其 slice_id 不一样。slice_id 是为了把大 bitmap 进行切分,减小每行 bitmap量级,可优化构建效率和内存使用量,同时也能够为分布式存储提供分片凭据。
insert into test.bitmap_test values ('2024-01-01', 0, 11, 'a', [1,2,3,4,5]), ('2024-01-02', 1, 11,'a', [11,12,13,14,15]); insert into test.bitmap_test values ('2024-01-01', 0, 11, 'b', [3,4,5,6,7,8]), ('2024-01-02', 1, 11,'b', [13, 14,15,16]); insert into test.bitmap_test values ('2024-01-01', 0, 12, 'c', [3,4,6,7,9]), ('2024-01-02', 1, 12,'c', [13,15,16,18]);
普通函数的使用和社区demo,以及其它函数并无差异。仅举几个例子。
SELECT arrayToBitmap([1, 2, 3, 4, 5]) FORMAT TSV -- 结果: {1,2,3,4,5}
SELECT bitmapToArray(uids) FROM test.bitmap_test WHERE tag_value = 'a' FORMAT TSV -- 结果: [11,12,13,14,15] [1,2,3,4,5] SELECT bitmapToArray(arrayToBitmap([1, 2, 3, 4, 5])) FORMAT TSV -- 结果: [1,2,3,4,5]
SELECT bitmapCardinality(arrayToBitmap([1, 2, 3, 4, 5])) FORMAT TSV -- 结果: 5
-- 求两个 bitmap 的交集 SELECT bitmapColumnAnd(uids) FROM test.bitmap_test WHERE (slice_id = 0) AND (tag_value IN ('a', 'b')) FORMAT TSV -- 结果: {3,4,5} -- 求两个 bitmap 的并集(两个函数同义) SELECT bitmapCardinality(bitmapColumnOr(uids)), bitmapColumnCardinality(uids) FROM test.bitmap_test WHERE (slice_id = 0) AND (tag_value IN ('a', 'b')) FORMAT TSV -- 结果: 8 8 -- 判断某个 bitmap中是否存在给定元素 SELECT bitmapColumnHas(uids, 12) FROM test.bitmap_test WHERE tag_value = 'a' FORMAT TSV -- 结果: 1
SELECT bitmapFromColumn(number) FROM ( SELECT number FROM system.numbers LIMIT 100, 10 ) FORMAT TSV -- 结果 {100,101,102,103,104,105,106,107,108,109}
用途:实现多个bitmap之间的复杂交并差运算。用户通过输入表达式表示出 bitmap 的运算,函数解析后进行对应计算。示例参考上文【聚合函数】- 【高阶聚合函数】小节的图例。
输入:编号列,bitmap列。编号列用于标识 bitmap,可以是表中字段(如 tag_id),也可以是人为定义变量(如 idx)。
表达式:一个编号锚定一个 bitmap。编号表达式是与或差操作,对应 bitmap的交并差运算。
支持的编号运算符:
输出:bitmap 交并差运算之后的结果 bitmap 中的元素个数。
Case 1: 求某个标签'a'总共元素个数:
SELECT bitmapColumnCardinality(uids) FROM test.bitmap_test WHERE tag_value = 'a' FORMAT TSV -- 结果: 10 -- 求标签'a'总共元素个数。等同于bitmapColumnCardinality的计算 SELECT bitmapCount('1')(If(tag_value = 'a', toInt32(1), toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test WHERE tag_value = 'a' FORMAT TSV -- 结果: 10 -- 求标签'a'总共元素个数,标签为字符串,可以直接用字符串表达式 SELECT bitmapCount('a')(tag_value, uids) FROM test.bitmap_test WHERE tag_value = 'a' FORMAT TSV -- 结果: 10
Case 2: 求两个标签的交集'a'和'b'
SELECT bitmapCardinality(bitmapColumnAnd(uids)) AS card FROM test.bitmap_test WHERE (tag_value IN ('a', 'b')) AND (slice_id = 0) FORMAT CSV -- 结果: 10 -- 等同于bitmapCardinality(bitmapColumnAnd)的计算 SELECT bitmapCount('1&2')(multiIf(tag_value = 'a', toInt32(1), tag_value = 'b', 2, toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test WHERE (tag_value IN ('a', 'b')) AND (slice_id = 0) FORMAT TSV -- 结果: 3 -- 上述sql的另一种写法,适合复杂sql嵌套 SELECT bitmapCount('1&2')(idx, uids) FROM ( SELECT toInt32(1) AS idx, uids FROM test.bitmap_test WHERE (slice_id = 0) AND (tag_value IN ('a')) UNION ALL SELECT toInt32(2) AS idx, uids FROM test.bitmap_test WHERE (slice_id = 0) AND (tag_value IN ('b')) ) FORMAT TSV -- 结果: 3
Case 3: 更多标签的交并差运算
-- 写法一 SELECT bitmapCount('1&2|3')(multiIf(tag_value = 'a', toInt32(1), tag_value = 'b', toInt32(2), tag_value = 'c', toInt32(3), toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test FORMAT TSV -- 结果: 11 -- 写法二:刚好 tag_value是字符串类型,可以使用字符串表达式 SELECT bitmapCount('a&b|c')(tag_value, uids) FROM test.bitmap_test FORMAT TSV -- 结果: 11
这个函数计算方法和bitmapCount是一样的,区别是它返回计算结果的bitmap, 不是个数。
至于怎么组合标签,等同于bitmapCount函数。bitmapCount 那里使用的是 tag_value 作为示例,这里展示一个 tag_id 作为示例的 case: 求两个标签的交集:
SELECT bitmapExtract('1&2')(multiIf(tag_id = 11, toInt32(1), tag_id = 12, 2, toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test WHERE (tag_id IN (1,2)) AND (slice_id = 0) FORMAT TSV -- 结果(没有交集): {} 另一种写法: SELECT bitmapExtract('11&12')(tag_id, uids) FROM test.bitmap_test WHERE (tag_id IN (1, 2)) AND (slice_id = 0) FORMAT TSV -- 结果(没有交集): {}
这个聚合函数再bitmapCount的基础上,支持了多组表达式。
用途:实现多个bitmap之间的复杂交并差运算,同时支持了多组运算和运算复用。用户通过输入表达式表示出 bitmap 的运算,函数解析后进行对应计算。示例参考上文【聚合函数】- 【高阶聚合函数】小节的图例。
输入:编号列,bitmap列。编号列用于标识 bitmap,可以是表中字段(如 tag_id),也可以是人为定义变量(如 idx)。
表达式:一个编号锚定一个 bitmap。编号表达式是与或差操作,对应 bitmap的交并差运算。同时可以提供多组表达式,函数依次执行对应计算,把多组结果一并返回。
支持的编号运算符:
输出:bitmap 交并差运算之后的结果 bitmap 中的元素个数。每个表达式对应一个结果,存储在数组中。
-- '_3|3'等价于 '(1&2)|3' SELECT bitmapMultiCount('1', '2', '1&2', '_3|3')(multiIf(tag_value = 'a', toInt32(1), tag_value = 'b', toInt32(2), tag_value = 'c', toInt32(3), toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test WHERE slice_id = 0 FORMAT TSV -- 结果: [5,6,3,6] -- tag_value 刚好是字符串类型,所以也可以使用字符串表达式 SELECT bitmapMultiCount('a', 'b', 'a&b', '_3|c')(tag_value, uids) AS card FROM test.bitmap_test WHERE slice_id = 0 FORMAT TSV -- 结果: [5,6,3,6]
_3表示复用了位置3处的表达式,即'1&2'。
有一组集合关系可以验证是否正确。该关系是
A + B = AUB + A交B
SELECT bitmapMultiCount('1', '2', '1&2', '1|2')(multiIf(tag_value = 'a', toInt32(1), tag_value = 'b', toInt32(2), tag_value = 'c', toInt32(3), toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test WHERE slice_id = 0 FORMAT TSV -- 结果: [5,6,3,8] -- tag_value 刚好是字符串类型,所以也可以使用字符串表达式 SELECT bitmapMultiCount('a', 'b', 'a&b', 'a|b')(tag_value, uids) FROM test.bitmap_test WHERE slice_id = 0 FORMAT TSV -- 结果: [5,6,3,8]
含义用户同bitmapMultiCount,差异点在返回值,返回 bitmap 数据。
SELECT bitmapMultiExtract('1', '2', '1&2', '1|2')(multiIf(tag_value = 'a', toInt32(1), tag_value = 'b', toInt32(2), tag_value = 'c', toInt32(3), toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test WHERE slice_id = 0 FORMAT TSV [{1,2,3,4,5},{3,4,5,6,7,8},{3,4,5},{1,2,3,4,5,6,7,8}] -- tag_value 刚好是字符串类型,所以也可以使用字符串表达式 SELECT bitmapMultiExtract('a', 'b', 'a&b', 'a|b')(tag_value, uids) FROM test.bitmap_test WHERE slice_id = 0 FORMAT TSV -- 结果: [{1,2,3,4,5},{3,4,5,6,7,8},{3,4,5},{1,2,3,4,5,6,7,8}]
用途:这个函数在bitmapMultiCount的基础上又加入了日期维度,可以在表达式中区别不同日期的标签。
注意日期列需要是 Int64 类型,一般日期用 Date类型,需要使用 toYYYYMMDD 函数进行转换。
输入:日期列,编号列,bitmap 列。
表达式:一个日期和一个编号组合锚定一个 bitmap,无法单独使用。所以日期_编号作为整体使用,如示例中的'20240101_1' 才能标识一个 bitmap。上文的函数bitmapMultiCount只需要'1'就可以,这是两者的差异点。
输出:bitmap 交并差运算之后的结果 bitmap 中的元素个数。每个表达式对应一个结果,存储在数组中。
SELECT bitmapMultiCountWithDate('20240101_1', '20240102_2', '20240101_1|20240102_2')(CAST(toYYYYMMDD(p_date), 'Int64') AS date1, multiIf((tag_value = 'a') AND (p_date = '2024-01-01'), toInt64(1), (tag_value = 'b') AND (p_date = '2024-01-02'), toInt64(2), (tag_value = 'c') and (p_date = '2024-01-01'), toInt64(3),toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test FORMAT TSV -- 结果: [5,4,9] -- tag_value刚好是字符串类型,所以可以使用字符串表达式 SELECT bitmapMultiCountWithDate('20240101_a', '20240102_b', '20240101_a|20240102_b')(CAST(toYYYYMMDD(p_date), 'Int64') AS date1, tag_value, uids) AS card FROM test.bitmap_test FORMAT TSV -- 结果: [5,4,9]
功能和用法同bitmapMultiCountWithDate,差异点在返回值,返回 bitmap 数据。
SELECT bitmapMultiExtractWithDate('20240101_1', '20240102_2', '20240101_1|20240102_2')(CAST(toYYYYMMDD(p_date), 'Int64') AS date1, multiIf((tag_value = 'a') AND (p_date = '2024-01-01'), toInt64(1), (tag_value = 'b') AND (p_date = '2024-01-02'), toInt64(2), (tag_value = 'c') and (p_date = '2024-01-01'), toInt64(3),toInt32(999)) AS idx, uids) AS card FROM test.bitmap_test FORMAT TSV -- 结果: [{1,2,3,4,5},{13,14,15,16},{1,2,3,4,5,13,14,15,16}] -- tag_value刚好是字符串类型,所以可以使用字符串表达式 SELECT bitmapMultiExtractWithDate('20240101_a', '20240102_b', '20240101_a|20240102_b')(CAST(toYYYYMMDD(p_date), 'Int64') AS date1, tag_value, uids) AS card FROM test.bitmap_test FORMAT TSV -- 结果: [{1,2,3,4,5},{13,14,15,16},{1,2,3,4,5,13,14,15,16}]