Apache Druid设计——Segment

Apache Druid在segment文件中存储数据指标,segment文件用时间参数划分分区。在基础设置中,会为每一个时间间隔创建一个segment文件,该时间间隔可以在granularitySpecsegmentGranularity参数中配置。为了让Druid在繁重的查询压力下保持良好的操作性能,应该让segment文件的大小在300mb至700mb之间。如果segment的文件大小超出了该值,就应该去改变时间间隔或者分区数据,并且对partitionsSpec中的targetPartitionSize参数做出调整(推荐优先设置这个参数为500万行)。

Segment文件的核心数据结构

接下来描述segment文件的内部结构:每一列的数据被存储在单独的数据结构中。通过分别存储每一列,Druid可以通过仅扫描某些真正会用到的列以达到降低查询延迟的目的。这里有三个基本的列类型,timestamp列,dimension列,metric列,如下图所示:
Apache Druid设计——Segment_第1张图片
timestamp列和metric列非常简单:在后端都是用LZ4压缩的整型或浮点型数组。一旦某个查询知道其该选择哪一个列后,它就会解压这些数据,拿出相关的行并执行其所需的聚合操作。如果该查询不需要某个列,那么这个列的数据就会被跳过。
Dimension列则不同,因为它支持过滤和Group by操作,所以每一个Dimension需要以下三个数据结构:

  1. 一个将值(作为string类型来对待)映射为ID的字典。
  2. 一个经过“1”中字典值映射后的list。
  3. 对于每个列中不同的值,用位图表示哪些行包含这个值。

那么,为什么是这样三个数据结构呢?
字典将字符串值映射为整型ID,是为了让“2”、“3”中的值可以被方便的表示出来。“3”中的位图,可以看作是用于快速过滤操作的反向索引(具体来说,位图可以快速处理AND和OR操作)。“2”中存储的值可用于Group by和TopN查询。换句话说,基于过滤且仅仅聚合指标的查询是不需要用“2”中存储的值的。
为了让大家对这些数据结构有个直观的感受,看一下上面示例数据中的“page”列。表示该Dimension的三个数据结构如下所示:

1: 对列值进行编码的字典
  {
    "Justin Bieber": 0,
    "Ke$ha":         1
  }

2: 编码后的列值
  [0,
   0,
   1,
   1]

3: 位图
  value="Justin Bieber": [1,1,0,0]
  value="Ke$ha":         [0,0,1,1]

需要注意的是位图与前两个数据结构不同,前两个数据的大小是会随着列数据大小增加而线性增加的,位图部分的数据大小依赖于列基数量。若高基数列非常稀少,则可高度压缩位图。Druid使用专用于位图压缩的压缩算法开发而成,如roaring位图压缩算法。

多值列

如果一个数据源使用了多值列,那么segment文件的数据结构则会看起来有所不同。接着以上述为例,第二行标记为 Justin BieberKe$ha,在该例中,三个数据结构应该如下所示:

1: Dictionary that encodes column values
  {
    "Justin Bieber": 0,
    "Ke$ha":         1
  }

2: Column data
  [0,
   [0,1],  <--Row value of multi-value column can have array of values
   1,
   1]

3: Bitmaps - one for each unique value
  value="Justin Bieber": [1,1,0,0]
  value="Ke$ha":         [0,1,1,1]
                            ^
                            |
                            |
    Multi-value column has multiple non-zero entries

注意“2”数据结构的第二行数据与“3”数据结构的Ke$ha位图的改变。如果数据某列中的某行有多个值,那么它在“2”数据结构中的那行是一个数组。另外,若在“2”数据结构中的某行有n个值,那么在位图中就会有n个非零值条目。

你可能感兴趣的:(大数据处理,Druid)