文章目录
一、前言
二、DataSource 结构
2.1 数据结构(维度列)
2.2 结构说明
三、Segment 结构
3.1 小总结
一、前言
与Druid 架构相辅相成的是其基于DataSource 与Segment 的数据结构,它们共同成就了Druid 的高性能优势。
二、DataSource 结构
若与传统的关系型数据库管理系统( RDBMS)做比较,Druid 的DataSource 可以理解为 RDBMS 中的表(Table)。DataSource 的结构包含以下几个方面。
时间列( TimeStamp):表明每行数据的时间值,默认使用UTC 时间格式且精确到毫秒级别。这个列是数据聚合与范围查询的重要维度。
维度列(Dimension):维度来自于OLAP 的概念,用来标识数据行的各个类别信息,参与事件过滤。
指标列( Metric):指标对应于OLAP 概念中的Fact,是用于聚合和计算的列。这些指标列通常是一些数字,计算操作通常包括Count、Sum 和Mean 等。
DataSource 结构 结构如图所示:
无论是实时数据消费还是批量数据处理, Druid 在基于DataSource 结构存储数据时即可选择对任意的指标列进行聚合( RollUp)操作。该聚合操作主要基于维度列与时间范围两方面的情况。
Druid读取数据的入口并不会直接存储原始数据, 而是使用Roll-up这种first-level聚合操作压缩原始数据。
下图显示的是执行聚合操作后DataSource 的数据情况。
相对于其他时序数据库, Druid 在数据存储时便可对数据进行聚合操作是其一大特点,该特点使得Druid 不仅能够节省存储空间,而且能够提高聚合查询的效率。
用SQL表示类似于对时间撮和所有维度列进行分组,并以原始的指标列做常用的聚合操作。
GROUP BY timestamp, publisher, advertiser, gender, country :: impressions = COUNT(1), clicks = SUM(click), revenue = SUM(price)
为什么不存原始数据? 因为原始数据量可能非常大,对于广告的场景,一秒钟的点击数是以千万计数。 如果能够在读取数据的同时就进行一点聚合运算,就可以大大减少数据量的存储,这种方式的缺点是不能查询单条事件,也就是你无法查到每条事件具体的click和price值了。
由于后面的查询都将以上面的查询为基础,所以Roll-up的结果一定要能满足查询的需求。通常count和sum就足够了,因此Rollup的粒度是你能查询的数据的最小时间单位。 假设每隔1秒Rollup一次,后面的查询你最小只能以一秒为单位,不能查询一毫秒的事件,默认的粒度单位是ms。
2.1 数据结构(维度列)
维度列因为要支持过滤和分组,每一个维度列的数据结构包含了三部分:
- 值到ID的Map映射
- 列的值列表,存储的是上一步对应的ID
- 倒排索引
示例进行说明:
代表这一维度列的数据结构如下:
1: Dictionary that encodes column values { "Justin Bieber": 0, "Ke$ha": 1 } 2: Column data [0, 0, 1, 1] 3: Bitmaps - one for each unique value of the column value="Justin Bieber": [1,1,0,0] value="Ke$ha": [0,0,1,1]
注意:在最坏情况下前面两种会随着数据量的大小而线性增长. 而BitMap的大小则等于数据量大小 * 列的个数。