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