浅析Dremel中嵌套数据记录的列式存储

什么是嵌套数据

嵌套数据举例如下,

图1 嵌套数据描述及举例,图片来源[1]

图1包含一个名为Document的数据结构的结构定义,即schema,以及两个实例,r1和r2。定义数据结构的schema有三种修饰符,如下:

● required:表示有且仅有一个值

● optional:表示可选,0到1个值

● repeated:表示重复,0到N个值


图2 记录r1的树形表示


所谓嵌套数据记录其实是一种树状结构,图2是数据记录r1的树形表示,其中叶子节点含有真正的值,字段可以用完整路径表示。图1所示的例子Document总共有六个字段,路径分别为:

● DocId

● Links.Backward

● Links.Forward

● Name.Language.Code

● Name.Language.Country

● Name.Url

记录按列存储主要有正向拆解和反向构造两个过程:

● 正向拆解:按照不同字段对记录进行拆解,相同字段的值集中存储为一列

● 反向构造:选择任意字段子集,重新构造为一个数据记录

repetition levels

因为嵌套数据记录的字段有重复,对于重复字段(repeated修饰)的多个值,在反向构造的时候,需要知道这些值是来自不同的记录,还是来自相同记录的重复字段。最简单的方式是引入一个“标志位”:0表示该值来自一个新的记录,1表示相同记录的重复字段。

然而重复字段是嵌套的,所以“相同记录的重复字段”包含多种情况,如图1所示record1,Code(en)(表示value为en的Code字段,下同)和Code(en-gb)都是记录r1的重复字段,它们在记录中的位置还需进一步加以区分。考虑到字段是用形如x.y.z…的路径表示,所以重复字段在记录中的“位置”,可以表示为“该重复字段出现在路径哪一级”。如果记录用树表示,那么所谓“路径哪一级”指的就是树的深度(levels)。需注意,路径中非repeated修饰的字段不参与深度计算。

比如Code字段的路径表示为Name.Language.Code,Name和Language都是重复字段,如果在记录中第一次出现,levels为0,如果在Name处重复出现,levels为1,在Language处重复出现levels为2。如Code(en)在Language处重复,所以levels为2;Code(en-gb)在Name出重复,所以levels为1。

又比如Forward字段路径为Links.Forward中,Links是optional的,不参与深度计算,Forward是repeated的,所以,如果在Forward处重复出现,levels为1(注意:不为2)。

这所谓的levels在Dremel中就是repetition levels,其定义如下:

“…  at what repeated field in the field’s path the

value has repeated.”

意思是“在路径中的什么重复字段,此值重复了”,通俗来说就是“在哪一级重复”。

图3 记录r1,r2的列存储结构,图片来源[1]

逐个读取列存储中的repetition

levels,就能够初步还原value在原有数据中的位置,以字段Name.Language.Code为例:

        1)第1个value是en-us,repetition levels=0表示没有任何重复,表明这是一个新的record的开始,也表明en-us处在第1个Name的第1个Language。

        2)第2个value是en,repetition levels=2表示en在Language重复,也就是说不在Name处重复,表明和上一个值en-us处在同一个Name,即en处在第1个Name的第2个Language

        3)第3个value是NULL,repetition levels=1表示NULL在Name处重复,表明NULL处在一个新的Name,第2个Name。之所以要插入一个NULL值,为了计算出第4个value‘en-gb’出现在第3个Name,否则的话就会被认为处在第2个Name

        4)第4个value是en-gb,repetition levels=1表示en-gb处在一个新的Name,即第3个Name

        5)第5个value是NULL,repetition levels=0表明这是一个新的记录的开始

Definition levels

如果value不为NULL,通过repetition levels就能够确定其所在位置。但如果value为NULL,仅有repetition levels还无法完全确定其所在位置。

以Name.Language.Country字段为例,第3个value是NULL,repetition

levels=1表明当前NULL处在第2个Name(需要结合前面两个value的repetition

levels计算得出)。但由于Name下面有两级定义,Language和Country,Language是repeated类型的,重复次数可能为0,即可能没有定义,Country是optional可选类型,也可能没有定义,既然都有可能没定义,仅有NULL就无法知道是在Language这一级NULL还是在Country这一级NULL。

因此,对于optional或repeated类型字段,需要一个标示显示的表明NULL型value定义在哪一级,这就是Dremel中的definition levels,定义如下:

“...how many fields in path that could be undefined (because they are

optional or repeated) are actually present in the record”

即“在路径中有多少个可选字段或重复字段实际上是有值的”。

         以图3所示Name.Language.Country为例进行说明:

● 第1个NULL value的definition levels为2,表示Name和Language有定义,Country没有定义

● 第2个NULL value的definition levels为1,表示Name有定义,Language就没有定义了

进一步看非NULL的value。Country为us和gb的value,其definition

levels为都3,表示Name、Language和Country都有定义。Name.Language.Code字段,Code为required类型,Name和Language是repeated类型,所以Code字段的definition levels取值1或2,value en-us、en、en-gb等definition levels为2,NULL value的defition为1。

不难发现,非NULL的value,其definition levels为路径深度的最大值。NULL的value,其definition levels都小于路径深度最大值。基于该特点,可以不用保存NULL value,仅保存其definition levels即可。

参考

[1] Dremel论文

你可能感兴趣的:(浅析Dremel中嵌套数据记录的列式存储)