【Druid】(三)Apache Druid 的数据结构2

简介: 【Druid】(三)Apache Druid 的数据结构2


2.2 结构说明


字典表的key都是唯一的,所以Map的key是unique的column value,Map的value从0开始不断增加。示例数据的page列只有两个不同的值。所以为Bieber编号0,Ke$ha编号为1。


Key            |Value
---------------|-----
Justin Bieber  |0
Ke$ha          |1

列的数据: 要保存的是每一行中这一列的值, 值是ID而不是原始的值。因为有了上面的Map字典,所以有下面的对应关系,这样列的值列表直接取最后一列: [0,0,1,1]。


rowNum  page                ID
1       Justin Bieber       0
2       Justin Bieber       0
3       Ke$ha               1 
4       Ke$ha               1


BitMap的key是第一步Map的key(列的原始值)。value数组的每个元素表示指定列的某一行是否包含/存在/等于当前key。注意:BitMap保存的value数组只有两个值:1和0,1表示这一行包含或等于BitMap的key, 0表示不存在/不包含/不等于,如下:


第一行的page列值为Justin Bieber/列值为Justin Bieber的在第一行里

^
                        |
value="Justin Bieber": [1,1,0,0]
value="Ke$ha":         [0,0,1,1]
                        ^
                        |
             第一行的page列值不是Ke$ha

   

这种存储方式,如果unique重复的列很少,比如page列的每一个值都是不同的。BitMap就会是一个稀疏矩阵。


A: [1,0,0,0,0,0,0,0,0,0,0]
B: [0,1,0,0,0,0,0,0,0,0,0]
C: [0,0,1,0,0,0,0,0,0,0,0]
D: [0,0,0,1,0,0,0,0,0,0,0]
E: [0,0,0,0,1,0,0,0,0,0,0]

unique的重复数量很少也叫做high cardinality,表示基数很高,不同列的数量很多,列值相同的记录数很少。


稀疏矩阵对于BitMap而言却是有优点的,因为越是稀疏,它可以被压缩的比例越大,最后存储的空间越少(相对原始数据)。


上面只是针对page列的BitMap,对于其他的维度列,都有自己的BitMap!即每一个维度列都有一个BitMap。


三、Segment 结构


DataSource 是一个逻辑概念, Segment 却是数据的实际物理存储格式, Druid 正是通过Segment 实现了对数据的 横纵向切割( Slice and Dice)操作。从数据按时间分布的角度来看,通过参数segmentGranularity 的设置,Druid 将不同时间范围内的数据存储在不同的Segment 数据块中,这便是所谓的数据横向切割。


这种设计为Druid 带来一个显而易见的优点:按时间范围查询数据时,仅需要访问对应时间段内的这些Segment 数据块,而不需要进行全表数据范围查询,这使效率得到了极大的提高。


Druid的分片是Segment文件。 Druid首先总是以时间戳进行分片,因为事件数据总是有时间戳。假设以小时为粒度创建下面的两个Segment文件。



通过Segment 将数据按时间范围存储,同时,在Segment 中也面向列进行数据压缩存储,这便是所谓的数据纵向切割。而且在Segment 中使用了Bitmap 等技术对数据的访问进行了优化。


  • 在几乎所有的NoSQL中都有数据分片的概念:比如ES的分片,HBase的Region,都表示的是数据的存储介质。为什么要进行分片,因为数据大了,不能都存成一个大文件吧,所以要拆分成小文件以便于快速查询,伴随拆分通常都有合并小文件。


  • 从Segment文件的名称可以看出它包含的数据一定是在文件名称对应的起始和结束时间间隔之内的。


  • Segment文件名称的格式:dataSource_interval_version_partitionNumber。最后一个分区号是当同一个时间戳下数据量超过阈值要分成多个分区。


  • 分片和分区都表示将数据进行切分。分片是将不同时间戳分布在不同的文件中,而分区是相同时间戳放不下了,分成多个分区。


  • 巧合的是Kafka中也有Segment和Partition的概念。Kafka的Partition是topic物理上的分组,一个topic可以分为多个partition,它的partition物理上由多个segment组成。即Partition包含Segment,而Druid是Segment包含Partition。


3.1 小总结


数据进入到Druid首先会进行索引,这给予了Druid一个机会可以进行分析数据,添加索引结构、压缩、为查询优化调整存储结构。


  1. 转换为列式结构
  2. 使用BitMap索引
  3. 使用不同的压缩算法


  • 索引的结果是生成Segment文件,Segment中除了保存不同的维度和指标,还保存了这些列的索引信息


  • Druid将索引数据保存到Segment文件中,Segment文件根据时间进行分片。最基本的设置中,每一个时间间隔都会创建一个Segment文件。


  • 这个时间间隔的长度配置在granularitySpec的segmentGranularity参数。为了Druid工作良好,通常Segment文件大小为300-700M。


  • 前面Roll-up时也有一个时间粒度:queryGranularity指的是在读取时就进行聚合,segmentGranularity则是用于分片进来之后的数据。


目录
相关文章
|
存储 分布式计算 druid
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(一)
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(一)
201 1
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(一)
|
消息中间件 存储 druid
大数据-156 Apache Druid 案例实战 Scala Kafka 订单统计
大数据-156 Apache Druid 案例实战 Scala Kafka 订单统计
219 3
|
存储 分布式计算 druid
大数据-155 Apache Druid 架构与原理详解 数据存储 索引服务 压缩机制
大数据-155 Apache Druid 架构与原理详解 数据存储 索引服务 压缩机制
266 3
|
消息中间件 分布式计算 druid
大数据-154 Apache Druid 架构与原理详解 基础架构、架构演进
大数据-154 Apache Druid 架构与原理详解 基础架构、架构演进
331 2
|
消息中间件 druid 大数据
大数据-153 Apache Druid 案例 从 Kafka 中加载数据并分析(二)
大数据-153 Apache Druid 案例 从 Kafka 中加载数据并分析(二)
186 2
|
消息中间件 分布式计算 druid
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(二)
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(二)
148 2
|
消息中间件 分布式计算 druid
大数据-153 Apache Druid 案例 从 Kafka 中加载数据并分析(一)
大数据-153 Apache Druid 案例 从 Kafka 中加载数据并分析(一)
226 1
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
307 59
|
6月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
140 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。

热门文章

最新文章

推荐镜像

更多