位图,就是位的集合,是一种数据结构,用bit位来存储数据的某种状态。在java中,一个int整型需要占据4个字节也就是32 bit位,这在运算时很方便。但如果在bitmap中,我们可以用对应的32 bit位对应存储32个十进制数,是最佳的数据压缩储存方式之一。
clickhosue对位图函数的讲解:
位图函数用于对两个位图对象进行计算,对于任何一个位图函数,它都将返回一个位图对象,例如and,or,xor,not等,可理解为与或非操作来实现的交集并集计算。
位图对象有两种构造方法。一个是由聚合函数groupBitmapState构造的,另一个是由Array Object构造的。同时还可以将位图对象转化为数组对象。我们使用RoaringBitmap实际存储位图对象,当基数小于或等于32时,clickhouse使用Set保存。当基数大于32时,clickhouse使用RoaringBitmap保存。这也是为什么低基数集的存储更快的原因。
bitmapBuild(array) → 将无符号整数数组构建位图对象。
bitmapToArray(bitmap) → 将位图转换为整数数组。
bitmapSubsetInRange(bitmap, range_start, range_end) → 将位图指定范围(不包含range_end)转换为另一个位图。bitmap – 位图对象,range_start – 范围起始点(含),range_end – 范围结束点(不含)。
bitmapSubsetLimit(bitmap, range_start, limit) → 将位图指定范围(起始点和数目上限)转换为另一个位图。bitmap – 位图对象,range_start – 范围起始点(含),limit – 子位图基数上限
测试:
WITH [toUInt32(1), toUInt32(2), toUInt32(5), toUInt32(7), toUInt32(35)] AS arr
SELECT
bitmapBuild(arr) AS bitmapBuild,
bitmapToArray(bitmapBuild(arr)) AS bitmapToArray,
bitmapToArray(bitmapSubsetInRange(bitmapBuild(arr), toUInt32(2), toUInt32(7))) AS bitmapSubsetInRange,
bitmapToArray(bitmapSubsetLimit(bitmapBuild(arr), toUInt32(2), toUInt32(7))) AS bitmapSubsetLimit
┌─bitmapBuild─┬─bitmapToArray─┬─bitmapSubsetInRange─┬─bitmapSubsetLimit─┐
│ # │ [1,2,5,7,35] │ [2,5] │ [2,5,7,35] │
└─────────────┴───────────────┴─────────────────────┴───────────────────┘
测试:
SELECT arrayJoin(bitmapToArray(bitmapBuild([1, 2, 3, 4, 5]))) AS uid
┌─uid─┐
│ 1 │
│ 2 │
│ 3 │
│ 4 │
│ 5 │
└─────┘
SELECT bitmapToArray(groupBitmapState(arrayJoin([1, 2, 3, 4, 5]))) AS groupBitmapState
┌─groupBitmapState─┐
│ [1,2,3,4,5] │
└──────────────────┘
测试:
# 语法格式
WITH
bitmapBuild([toUInt32(1), toUInt32(2), toUInt32(3), toUInt32(4), toUInt32(5)]) AS bitmap1,
bitmapBuild([toUInt32(4), toUInt32(5), toUInt32(9), toUInt32(17), toUInt32(35)]) AS bitmap2
SELECT
bitmapHasAny(bitmap1, bitmap2) AS bitmapHasAny,
bitmapHasAll(bitmap1, bitmap2) AS bitmapHasAll
┌─bitmapHasAny─┬─bitmapHasAll─┐
│ 1 │ 0 │
└──────────────┴──────────────┘
测试:
WITH
bitmapBuild([toUInt32(1), toUInt32(2), toUInt32(3), toUInt32(4), toUInt32(5)]) AS bitmap1,
bitmapBuild([toUInt32(4), toUInt32(5), toUInt32(9), toUInt32(17), toUInt32(35)]) AS bitmap2
SELECT
bitmapContains(bitmap1, toUInt32(5)) AS bitmapContains,
bitmapToArray(bitmapAnd(bitmap1, bitmap2)) AS bitmapAnd,
bitmapToArray(bitmapOr(bitmap1, bitmap2)) AS bitmapOr,
bitmapToArray(bitmapXor(bitmap1, bitmap2)) AS bitmapXor,
bitmapToArray(bitmapAndnot(bitmap1, bitmap2)) AS bitmapAndnot
┌─bitmapContains─┬─bitmapAnd─┬─bitmapOr────────────┬─bitmapXor───────┬─bitmapAndnot─┐
│ 1 │ [4,5] │ [1,2,3,4,5,9,17,35] │ [1,2,3,9,17,35] │ [1,2,3] │
└────────────────┴───────────┴─────────────────────┴─────────────────┴──────────────┘
测试:
WITH bitmapBuild([toUInt32(4), toUInt32(5), toUInt32(9), toUInt32(17), toUInt32(35)]) AS bitmap
SELECT
bitmapCardinality(bitmap) AS bitmapCardinality,
bitmapMin(bitmap) AS bitmapMin,
bitmapMax(bitmap) AS bitmapMax
┌─bitmapCardinality─┬─bitmapMin─┬─bitmapMax─┐
│ 5 │ 4 │ 35 │
└───────────────────┴───────────┴───────────┘
测试:
WITH
bitmapBuild([toUInt32(1), toUInt32(2), toUInt32(3), toUInt32(4), toUInt32(5)]) AS bitmap1,
bitmapBuild([toUInt32(4), toUInt32(5), toUInt32(9), toUInt32(17), toUInt32(35)]) AS bitmap2
SELECT
bitmapOrCardinality(bitmap1, bitmap2) AS bitmapOrCardinality,
bitmapXorCardinality(bitmap1, bitmap2) AS bitmapXorCardinality,
bitmapAndnotCardinality(bitmap1, bitmap2) AS bitmapAndnotCardinality,
bitmapAndCardinality(bitmap1, bitmap2) AS bitmapAndCardinality
┌─bitmapOrCardinality─┬─bitmapXorCardinality─┬─bitmapAndnotCardinality─┬─bitmapAndCardinality─┐
│ 8 │ 6 │ 3 │ 2 │
└─────────────────────┴──────────────────────┴─────────────────────────┴──────────────────────┘
Roaringbitmap可以对数据进行压缩储存以及利用位运算提高查询性能,所以RoaringBitmap常用于处理大量数据的排序、查询以及去重。举例,在用户画像中,利用bitmap储存用户Id的人群包,同时利用位运算的与或非操作来计算多个人群包的交集并集,从而得到新人群。
参考文章:clickhouse官方文档