1、什么是bitmap
bitmap的介紹:https://www.cnblogs.com/cjsblog/p/11613708.html
2、Clickhouse的RoaringBitmap介紹
https://blog.csdn.net/yizishou/article/details/78342499
3、基於bitmap實現業務需求
我們的需求場景是:任意時間段, 求關注的人群基數(去重)
如果使用傳統數倉按天分區做法,成本會非常高,而且無法做到在線查詢出結果的
簡單解釋下:
2021-01-01這一天 關注的iphone12的人是 : [張三、王五、趙六]
2021-01-02這一天 關注的iphone12的人是 : [王五、趙六、陳七]
求這兩天關注過iphone12的人數量:
[張三、王五、趙六]
or
[王五、趙六、陳七]
然后去重,得到:
[[張三、王五、趙六、陳七]
求2021-01-01到2021-01-02的留存人數:
[張三、王五、趙六]
and
[王五、趙六、陳七]
相交得到:
[王五、趙六]
求2021-01-02 相比 2021-01-01的新增人數
[王五、趙六、陳七] andNot [張三、王五、趙六] 在2021-01-02出現過,但沒有在2021-01-01出現過的人 [陳七]
以上的操作如果要通過Clickhouse實現,需要如下幾步:
第一步:在clickhouse形成滿足需求的寬表
第二步:基於寬表實現bitmap表
第三步:實現需求查詢的sql
3.1、實現業務寬表
我們實現寬表的方式是:Hive加工處理,得到業務寬表,然后經過Datax將數據同步到Clickhouse里面
比如,按照上面的邏輯,實現的寬表就是(clickhouse的表):
{
dt string 時間
brand 品牌 手機品牌
phone_model 手機型號
device_id String 設備號
}
【注意】:這一步后續是可優化的,要結合bitmap的特性和clickhouse的表引擎來優化
3.2、基於寬表實現bitmap表
clickhouse的bitmap函數頁面:https://clickhouse.com/docs/zh/sql-reference/functions/bitmap-functions/
簡單分析下需求,我們要取品牌、型號、天維度下的人群基數
那么Clickhouse的bitmap表可以做成如下結構:
{ dt LowCardinality(String) 時間 dim_type LowCardinality(String) 維度類型(1:品牌維度、2:手機型號維度) dim_value LowCardinality(String) 每個dim_type維度下對應的品牌或者手機型號值 bitmap_dvid AggregateFunction(groupBitmap, UInt32) 明細 }
然后通過jdbc或者sparkSQL,實現如下操作,向clickhouse的bitmap表插入數據:
1):插入數據前,刪除分區
alter table bitmap的表 on cluster default_cluster drop partition 時間分區
2):分別插入不同維度的bitmap
插入品牌維度: INSERT INTO bitmap表 select dt , 1 , brand , groupBitmapState(toUInt32(dvid)) as dvid from 寬表 where dt = 日期 group by brand 插入型號維度 INSERT INTO bitmap表 select dt , 2 , phone_model , groupBitmapState(toUInt32(dvid)) as dvid from 寬表 where dt = 日期 group by phone_model
3):查詢新增、留存等
查詢iphone12品牌在當前周期(2021-07-01~2021-09-29)相比上周期(2021-05-01 ~ 2021-06-30)的留存人數 select bitmapCardinality( bitmapAnd( select groupBitmapOrState(devid_bmp) from( select devid_bmp from bitmap表 where dt >= '2021-07-01' and dt <= '2021-09-29' and dim_type = 1 and dim_value = 'iphone12' ) , -- 當期周期關注過iphone12的人 select groupBitmapOrState(devid_bmp) from( select devid_bmp from bitmap表 where dt >= '2021-05-01' and dt <= '2021-06-30' and dim_type = 1 and dim_value = 'iphone12' ) -- 上周期關注過iphone12的人 ) )
經過測驗:一個月的人群數量大約是:1億
通過bitmap查詢留存,一個月的情況,不到2s
4、優化bitmap在clickhouse上的使用
4.1、引擎上的選擇
首先是引擎上的選擇,實際壓測,發現兩種引擎在bitmap場景下效率最高,分別是:
1、MergeTree
2、ReplicatedMergeTree
其中使用MergeTree性能會更好
4.2、縮減bitmap的大小
我們的設備明細一般是64位的,經過hash散列后,占用的bitmap空間其實是非常大的
所以我們對所有的設備明細維護了一套數字(其實就是hive的row_number)
這樣bitmao大大縮減,極大提升查詢速度,減小了每次查詢使用的CPU和內存

