Parquet的Repetition Level和Definition Level
如下的 schema 定义了每行是一个组合类型Document:(required表示必须有,optional表示可选,repeated表示可重复的,即数组(数组长度可以是0)。group类似于struct)
message Document { required int64 DocId; optional group Links { repeated int64 Backward; repeated int64 Forward; } repeated group Name { repeated group Language { required string Code; optional string Country; } optional string Url; } } |
假设有两行数据如下:
DocId: 10 Links Forward: 20 Forward: 40 Forward: 60 Name Language Code: 'en-us' Country: 'us' Language Code: 'en' Url: 'http://A' Name Url: 'http://B' Name Language Code: 'en-gb' Country: 'gb' |
DocId: 20 Links Backward: 10 Backward: 30 Forward: 80 Name Url: 'http://C' |
如果是关系型数据,而不是嵌套的结构。存储的时候,我们可以将每一列的值直接排列下来,不用引入其他的概念,也不会丢失数据。对于嵌套的结构,我们 还需要两个变量R (Repetition Level) ,D (Definition Level) 才能存储其完整的信息。
在Parquet中我们只需定义和存储schema的叶子节点所在列的Repetition Level和Definition Level
先对repeated或optional的类型没有值的列用null填充(不填充会导致反解析时错位),如下:
DocId: 10 Links Backward: null Forward: 20 Forward: 40 Forward: 60 Name Language Code: 'en-us' Country: 'us' Language Code: 'en' Country: null Url: 'http://A' Name Language Code: null Country: null Url: 'http://B' Name Language Code: 'en-gb' Country: 'gb' Url: null |
DocId: 20 Links Backward: 10 Backward: 30 Forward: 80 Name Language Code: null Country: null Url: 'http://C' |
Repetition Level是记录该列的值是在某行的哪一个级别上重复的。比如对于Name.Language.Code,一共有5条记录。
- en-us,出现在第一个Name的第一个Lanuage里面。在此之前,这三个元素是没有重复过的,都是第一个。所以其R为0。
- en, 出现在第一个Name的第二个Lanuage里面。也就是说Lanague是重复的元素。Name.Language.Code中Lanague排第二个,所以其R为2.
- null, 出现在第二个Name的第一个Language里面,Name是重复元素,排第一个,R为1
- en-gb,出现在第三个Name的第一个Language里面,Name是重复元素,排第一个,所以其R为1。
- null, 出现在第一个Name的第一个Lanuage里面。在此之前,这三个元素是没有重复过的,都是第一个。所以其R为0。
从Repetition Level的定义上可以看出,每次R=0表示新的一行开始了。只有repeated类型的field需要Repetition Level,optional和required类型的不需要。
另外,按我的理解,比较 Links.Forward(是repeated类型)和Name.Language.Code(不是repeated类型)。
- 对于repeated类型的Repetition Level,是指这个值和上一值同属于哪一层元素。
- 对于非repeated类型的Repetition Level,是指这个值和上一值在哪一层元素上重复。
不知道对不对,后续验证。
Definition Level是定义的深度,用来记录该列是否是”想象”出来的。所以对于非NULL的记录,是没有意义的,其值必然为相同。例如Name.Language.Country,一共有5条记录。
- us,真实存在的,D为3.
- null,到Language这层是真实存在的,D为2.
- null,到Name这层是真实存在的, D为1
- gb,真实存在的,D为3
- null,到Name这层是真实存在的,D为1
如果路径中有required,可以将其减去,因为required必然会define,记录其数量没有意义,比如Name.Language.Code的Definition Level。
接下来如果可以根据scheme和结构图反推为原始数据,那说明对这个Repetition Level和Definition Level已经完全理解。
message Document { required int64 DocId; optional group Links { repeated int64 Backward; repeated int64 Forward; } repeated group Name { repeated group Language { required string Code; optional string Country; } optional string Url; } } |
以第一行为例
1) DocId
10
2) Links. Forward
第一行有三个值,r分别是0,1,1,后面两个1表示是在第一个元素里面重复,也就是Links,得到:
DocId: 10 Links Forward: 20 Forward: 40 Forward: 60 |
3) Links. Backward
第一行只有一个NULL值,d=1表示在Links这层有定义,得到
DocId: 10 Links Forward: 20 Forward: 40 Forward: 60 Backward: null |
实际上和上一步得到的结果是一样的,红色字体是空值,只是为了理解方便。
4) Name.Url
第一行有三个值。由于Url不是repeated类型的,所以和Links.Forward是不一样的。Url是在Name这一层重复。
DocId: 10 Links Forward: 20 Forward: 40 Forward: 60 Backward: null Name Url: 'http://A' Name Url: 'http://B' Name Url: null |
5) Name.Language.Code
第一个en-us在第一个Name的第一个Language下。
第二个en,和第一个在第2个元素上重复,由于Code不是repeated类型,所以和第一个在不同的Language下,但是在同一个Name下。
第三个null,和第二个在第1个元素上重复,而定义层次d是1,也就是只在Name上有定义,Language开始就没定义
第四个en-gb,和第三个在第1个元素上重复,所以属于第三个Name的Language下。
DocId: 10 Links Forward: 20 Forward: 40 Forward: 60 Backward: null Name Url: 'http://A' Language Code: en-us Language Code: en Name Url: 'http://B' Language Code: null Name Language Code: en-gb Url: null |
6) Name.Language. Country
第一个us在第一个Name的第一个Language下。
第二个null,和第一个在第2个元素上重复,由于Country不是repeated类型,所以和第一个在不同的Language下,但是在同一个Name下。而定义层次d是2,也就是Language那层有定义。
第三个null,和第二个在第1个元素上重复,而定义层次d是1,也就是只在Name上有定义,Language开始就没定义
第四个gb,和第三个在第1个元素上重复,所以属于第三个Name的Language下。
DocId: 10 Links Forward: 20 Forward: 40 Forward: 60 Backward: null Name Url: 'http://A' Language Code: en-us Country: us Language Code: en Country: null Name Url: 'http://B' Language Code: null Country: null Name Language Code: en-gb Country: gb Url: null |