天天看點

ClickHouse實作Bitmap類函數算法RoaringBitmap

作者:大狗在海裡

0.抛出大資料老生常談問題

給定含有40億個不重複的位于[0,2^32-1]區間内的整數集合,如何快速判定某個數

是否在該集合内?

用什麼結構? Bloom Filter,HyperLogLog…bitmap是基礎

為撒用位圖? 省空間-- 16g,500mb

缺點是什麼?連續整數的問題

1.ClickHouse的bitmap實作算法roaringbitmap

将32位無符号整數按照高16位分桶,即最多有2^16即65536個桶,也就是container。

存儲資料時,按照資料的高16位找到container,如果沒有就建立一個,再将低16位放入container中

ArrayContainer —-小于4096

BitmapContainer —大于4096

RunContainer —連續存儲優化

2.Bitmap類函數介紹

函數功能介紹

利用聚合函數groupBitmap的groupBitmapState方法,可以将Integer類型的字段轉換成Bitmap

利用bitmapBuild方法,傳入Array類型,可以将其轉換為Bitmap

另外,其它的方法主要是用于Bitmap自身或之間的位運算,Bitmap與Array雙向轉換。

groupBitmap:傳回的是對應列的cardinality值

groupBitmapState:傳回對應整數列的bitmap類型,相當于是将對應列的所有值以Array類型組織,再調用bitmapBuild函數

bitmapAnd: 從運算角度看是進行按位與操作,從sql角度看就是兩部分的條件都要滿足

bitmapOr:從運算角度看是進行按位或操作,從sql角度看就是兩部分的條件任意滿足一個即可

bitmapXor:從運算角度來看是進行按位異或操作(相同為0相異為1),從sql角度看就是滿足條件A不滿足條件B或者滿足條件B而不滿足條件A

bitmapAndnot:從運算角度來看是進行按與非,從sql角度看使用者當作流失使用者

—注意規避問題

select 

--僅僅支援UInt32(42億+整型,int32 21億+)

bitmapContains(groupBitmapMergeState(uv),toUInt32(9379716501)) as is_exists, 

has(bitmapToArray(groupBitmapMergeState(uv)),9379716501) as array_is_exists 

from user_tags_bitmap where tag='user_first_dt' and value='20230310'

3.實際案例-使用者标簽用bitmap存儲應用

#利用clickhouse bitmap高效能力分析使用者行為場景

select

arrayJoin(bitmapToArray(bitmapAnd(hot_b,cold_b))) as "數組轉行list",

bitmapToArray(bitmapAnd(hot_b,cold_b)) as "留存使用者",

bitmapCardinality(bitmapOr(hot_b,cold_b)) as "全部使用者",

bitmapCardinality(bitmapAnd(hot_b,cold_b)) as "留存數",

bitmapAndCardinality(hot_b,cold_b) as "留存數--優秀寫法",

bitmapCardinality(bitmapAnd(hot_b,cold_b))/bitmapCardinality(hot_b) as "留存率",

bitmapAndnotCardinality(hot_b,cold_b) as "流失使用者數",

bitmapCardinality(bitmapAndnot(hot_b,cold_b))/bitmapCardinality(hot_b) as "流失率",

bitmapAndnotCardinality(cold_b,hot_b) as "新使用者數"

from

(

select 1 as join_id,groupBitmapMergeState(uv) as hot_b

from user_tags_bitmap where tag='app_login_date' and value='2023-03-10'

) hot

join

(

select 1 as join_id,groupBitmapMergeState(uv) as cold_b

from user_tags_bitmap where tag='app_login_date' and value='2023-03-17'

) cold on hot.join_id=cold.join_id

繼續閱讀