🗒️Parquet(2)striping and assembly 算法
2023-7-28
| 2023-8-21
字数 1204阅读时长 4 分钟
type
status
date
slug
summary
tags
category
icon
password
这个算法解决的是基于列式存储,Parquet 是如何支持嵌套格式的问题。

支持复杂格式

在嵌套格式里,可能会出现 List、Map 之类的结构,Parquet 使用 required、optional、repeated 三个字段去支持这些结构。含义分别代表:
  • required:有且只有一次
  • optional:0 或 1 次
  • repeated:0 或多次
对于 List 可以参考下面这个格式定义:
对于 Map 可以参考下面这个格式定义:
当然, List 和 Map 还可以互相嵌套。

Repetition Level

使用列式存储遇到的第一个问题是如何区分两段数组,例如对于下面这条数据:
对应的结构如下,代表 list 和 element 都是可以重复的字段:
按照列式存储的思想,我们会把 list.lower 这个字段的数据都存储在一起,即
问题来了,我们不能判断 b、c、d、e 究竟是属于前一个 list 还是后一个 list。 Parquet 使用 repetition level 来解决这个问题。
repetition level 只与 repeated 类型的字段有关,例如,起始的嵌套层级是 level 0,在上面这个例子,还有另外两层嵌套:list 是 level 1,element 是 level 2。
repetition level 记录的是嵌套层级的变化:
1)如果当前值是一个新数组的开始,repetition level 值等于重复开始的嵌套层级。
2)如果当前值不是一个新数组的开始,repetition level 值等于这个字段的嵌套层级。
上面的例子里,对应的编码如下:
list.lower
repetition level
a
0
b
2
c
1
d
2
e
2
说明如下:
1)a 是新数组的开始,但是因为没有前一个数组,它的 repetition level 是 0;
2)c 是新数组的开始,前一个数组是在 list 层重复,它的 repetition level 是 1;
3)其他字母不是新数组的开始,它们是在 element 层重复,它的 repetition level 就是 2。
如果嵌套层级不等于它实际的层级,说明开始了一个新数组。因此,这里的 a、c 截断出了两个数组。

Definition Level

只有 Repetition Levels 还存在一个问题,那就是不能处理字段为空的情况。
以下面这个情况为例:
考虑对 list.upper 字段进行按列存储,因为第一个 list 里没有保存 upper 字段,最后一条数据也没有出现 upper 字段,都用 null 代替,得到:
对应的编码如下:
list.upper
repetition level
null
0
C
0
D
2
E
2
null
0
这样,仅凭 repetition level 字段,不能知道第一个 upper 是在已经定义好的 list 里面的,而第二个 upper 则是没有 list 定义的。使用 definition level 可以表达 null 的位置。
definition level 的值等于该列的路径上标示为 optional 或者 repeated 的个数。
list.upper
definition level
null
1
C
2
D
2
E
2
null
0
说明如下:
1)第一个 null 的路径上有一个 repeated (list), definition level = 1;
2)C、D、E的路径上有两个 repeated(list、upper), definition level = 2;
3)第一个 null 的路径上没有 repeated, definition level = 0。
这样,通过 definition level 我们可以知道 null 值究竟代表在哪个层级上的这个字段为空。
并且,Parquet 还可以不存储这个 null 值,只要是 definition level 值小于这个列路径上的 optional + repeated 个数,那么说明这个列一定是没有定义,null 值可以不保存。

总结

在存储时根据每列的情况把 Repetition Levels 和 Definition Levels 两个字段一起加上去。在读取文件时根据 Repetition Levels 和 Definition Levels 两个字段就可以把数据还原回来了,这就是 striping and assembly 算法。
需要说明的是,为每个值都加上 repetition level 和 definition level 两个字段可能带来性能损耗,Parquet 做很多的优化措施,并且也通过特别的编码对这部分数据进行了压缩。
 
最后,给出这个方法提出时用的例子,大家可以根据上面的理解去分析这两个字段的值:
notion image
 
 
  • Parquet
  • Parquet(1)概述Parquet(3)谓词下推
    Loading...