1、整体视野感受
parquet的存储格式:
官方给的结构图:
2、解读
2.1 Header与Magic Number
Header只有4个字节(4Byte),本质是一个magic number,用来指示文件类型。magic number 目前有两种变体,分别是“PAR1”和“PARE”。
PAR1 代表普通的parquet文件;
PARE 代表加密过的Parquet 文件。
通过两张图对比,可以看出Header 对应 Magic Number。
2.2 Index
Index是Parquet文件的索引块,主要是为了支持“谓词下推”(Predicate Pushdown)功能。
Parquet文件自带Max-Min索引,Spark可以根据每个Page的max和min 值选择是否要跳过这个Page,不用读取则对应减少I/O开销。
Parquet 自带两种索引:Max-Min 统计信息 和 BloomFilter。
Max-Min索引是对每个Page都记录它所含数据的最大值和最小值。这样某个Page是否不满足查询条件就可以通过Max-Min值来判断;BloomFilter 则是对Max-Min的补充。针对value比较稀疏,Max-Min范围比较大的列,用Max-Min索引的效果就不太好,BloomFilter可以克服这一点。
2.3 Footer
Footer 是Parquet原数据(metadata)的大本营,包含了如schema,Block的offset和size,Column Chunk的offset 和 size等所有重要元数据。
Footer 还承担了整个文件入口的职责,读取Parquet文件的第一步就是读取Footer 信息,转化成元数据后,在根据这些元数据跳转到对应的block和column,读取真正的数据。
2.4 Row Group
数据分片就是Row Group。数据太大,进行水平切分。切分的依据是根据HDFS存储数据的单位是Block,默认大小是128MB,如果不对数据进行水平切分,只要数据量足够大(超过128MB),一条record的数据就会跨越多个Block,会增加I/O开销。
所以建议HDFS的block size 设置为1GB,同时把Parquet的parquet.block.size 设置为1GB,目的就是一个Row Group正好存放在一个HDFS 的 Block里。
2.5 Column Chunk
(垂直切分)把一个数据拆成多列,每一列的数据所构成的分片就是Column Chunk。
2.6 Page
对Column Chunk进行最后一次水平切分,分解为一个个的Page(最小数据单元),默认大小为1MB。此次操作的目的是便于单挑数据或者小批量数据的查询。因为Page是Parquet 文件最小的读取单位,同时也是压缩的单位。