druid 数据存储分为三部分
timestamp、dimensions、metrics
其中,timestamp、metrics部分是采用lz4直接压缩
但是dimensions部分需要支持过滤查询以及分组查询。所以dimensions部分的每个维度都采用了以下三种数据结构做转码,存储
- A dictionary that maps values (which are always treated as strings) to integer IDs,
- For each distinct value in the column, a bitmap that indicates which rows contain that value, and
- A list of the column’s values, encoded using the dictionary in 1
举个例子,源数据如下:
timestamp(timestamp) | name(dimensions) | city(dimensions) | province(dimensions) | age(metric) | wage(metric) |
2015-04-18T04:02:10Z | 张三 | 北京 | 北京 | 24 | 12000 |
2015-04-18T05:22:10Z | 李四 | 深圳 | 广州 | 30 | 30000 |
2015-04-18T08:45:14Z | 李四 | 长沙 | 湖南 | 21 | 8000 |
2015-04-18T07:12:10Z | 张三 | 深圳 | 广州 | 28 | 20000 |
name列来说
1: Dictionary that encodes column values
{
"张三": 0,
“李四": 1
}
2: Column data
[0,
1,
1,
0]
3: Bitmaps - one for each unique value of the column
value="张三": [1,0,0,1]
value=“李四": [0,1,1,0]
数据结构2只用于存储编码时,转成数据结构3时,2就没有用了。所以最终存的只有数据结构1和3
当然,dimensions列中也支持多值模式。想象一下,如果上面表格中的第二行,name的值包括了’张三’和’李四’,那么会是这样的结果
1: Dictionary that encodes column values
{
"张三": 0,
“李四": 1
}
2: Column data
[0,
[0,1], <--Row value of multi-value column can have array of values
1,
0]
3: Bitmaps - one for each unique value of the column
value="张三": [1,1,0,1]
value=“李四": [0,1,1,0]
查询解码过程。
如果我们查询name=‘张三’的工资,首先会检索数据结果1中,是否包含’张三’,如果有,再查询张三对应的数据结构3,找出值为1的列,再对应的找出metric中wage的值,最后得到12000,20000