bitmap是什么
時序數據庫支持多維查詢,一般來講,兩種方式,一種是倒排索引,ES使用的;一種是bitmap索引,druid就在使用這種方式。bitmap是個什么?一種使用bit位來存儲value,可以節省很大空間,在查詢時也能通過與或關系快速查詢。
舉個例子來看,bitmap是怎么來加速多維查詢的。數據如下
| 時間 | 城市 | 性別 | 曝光次數 |
| 2020-01-01 13:13:13 | CCC | gender | 1 |
| 2020-01-01 13:14:13 | BBB | female | 1 |
| 2020-01-01 13:15:13 | CCC | female | 1 |
時間是時序列,城市、性別是維度,曝光次數是指標值。這時如果有個多維查詢,select 曝光 from xxx where 城市='CCC' and 性別='female'
如果不使用索引,只能全表掃描,將符合條件的取出來。如果使用bitmap可以直接取出來就是第三行,不需要掃描全表去一一比對。
bitmap的基本原理是將值映射的bit位上,再采用或/與的操作,快速定位符合條件的行,如上面兩個維度可變為如下bitmap:
| 城市 | 性別 | ||
| CCC | 101 | gender | 100 |
| BBB | 010 | female | 011 |
原數據行數為3行,bitmap的大小為3,每一位代表每行的的值是否存在。所以維度值有多少個,bitmap就有多少個。比如CCC的101,代表第一行和第三行的值為CCC。所以在查詢的時候,通過bimap對應的與操作,條件為 where 城市='CCC' and 性別='female',轉換成bitmap計算為:
101 and 011,得到001,所以得出第三行符合條件。查到第三行后,再取出第三行對應的曝光值即可。
druid怎么構建bitmap索引
1.構建時機
druid有實時節點和歷史節點,那索引的構建是在數據寫入的時候還是在數據從內存持久化到硬盤的時候呢? 寫入的時候構建,肯定會影響寫入性能。但是批量構建的時候,實時寫入到內存的那部分數據就需要另一套索引機制來進行查詢,在實際查詢中需要分別處理。druid采用的是后者。
2.構建維度字典
維度字典通常維護映射值,主要兩個map映射,valueToId,IdToValue的映射,比如性別列,維護<gender,0>、<female,1>的一個map,再維護反過來的一個map。維度字段通常是給維度值一個自增的Int值。
3.構建bitmap
每個維度列會維護一個bitmap 數組,bitmap數組的大小對應維度值的個數。每個維度值都會對應一個bitmap。每個維度值對應的數組下標和上文的維度字典有關。比如gender的維度字段的值為0,所以的bitmap數組的下標即為0.
構建過程為:
1.為每一行生產一個自增的rowNum;
2.遍歷所有的列,分別為每個維度構建相應的bitmap數組,針對每個維度的value,先在維度字典中找到對應的下標值,然后構建/找到對應下標的bitmap。找到維度值的bitmap后,再講bitmap的下標為rowNum的bit位置為1,代表該行存在這個值。
具體過程:
1.性別維度列維護了一個bitmap數組,數組大小為2,其中下標為0對應gender的bitmap,下標為1對應female的bitmap。初始化時,兩個bitmap中沒有任何數字;
2.遍歷第一行(rowNum為0),值為gender,根據維度字典找到對應的下標0的bitmap,然后將bitmap中下標為0的位置為1,得到;
gender:1
female:
3.遍歷第二行(rowNum為1),值為female,根據維度字典找到對應下標為1的bitmap,然后將bitmap中下標為1(rowNum)的位置為1,得到:
gender:1
female:01
4.遍歷第三行(rowNum為2),值為female,根據維度字段找到下標為1的bitmap,然后將bitmap中下標為2(rowNum)的位置為1,得到:
gender:1
female:011
這樣就得到gender的bitmap索引,其他維度列構建的方式一樣。
壓縮
上文構建bitmap的過程可以看到,bitmap的長度和行數有關系,如果幾十億上百億的數據,bitmap的長度也要這么長嗎? 在實際存儲是,比如性別,城市這種,會存在很多連續的值,比如剛才的例子中,第二行和第三行的值一樣,是否可以采用壓縮的方式來減少數據的存儲? roaringbitmap比較推薦,能夠壓縮且對查詢效率的影響不大。
bitmap如何持久化
druid的原始數據每隔一段時間就會落盤一次,原始數據落盤時,對應的bitmap索引也需要進行落盤。druid會首先將維度字典持久化到磁盤,再講原始數據持久化為文件(原始數據對應的值已經通過維度字典替換),再講bitmap索引持久化到文件。
druid系統是列式存儲,同一個segment中所有列的數據都會分別獨立存儲在一起形成多個文件,比如性別列會存儲在一起形成文件,曝光列會存在一起形成文件。
druid文件分為兩種,一種是定長的,比如維度列是經過維度字典編碼的,都是int類型的,double列,Long列都是存數值類型。一種是非定長的,比如維度字典中存儲的維度值,bitmap索引中存儲的bitmap數據的值也不是定長的。
