Parquet

Columnar storage

像文本、关系型数据库的表这种数据存储方式都是基于row的,这意味着所有的字段都从第一行开始写,然后写第二行,以此类推。诸如JSON、XML、Avro这种 row storage数据序列化存储格式也是基于行存储的。

而列存储的设计,数据存储首先按列存储,然后按行存储。所有记录的第一个字段的值先被写入,然后是第二个字段,以此类推。下面图片可以很形象的说明这两者的不同之处。

使用列存储主要有两大好处:

  1. 系统读取列式存储的数据时,能够快速的提取列的子集,降低I/O。而基于行的存储系统在读取数据时,通常需要读取整行,即使需要的只有一两列字段。
  2. 采用列式存储数据是有很多优化手段,比如run-length encoding 和 bit packing可以效率的压缩数据的size,节省存储空间。通常的压缩格式也可以很好的应用于列式存储,因为同一列的数据类型是一样的。

Hadoop中,诸如JSON、Avro这种数据存储格式都是基于行式存储的,那么很多可以应用在列式存储格式上的优化手段都变的不可用。如果上图是一张Hive表,那么执行一个查询:

SELECT AVG(price) FROM stocks;
  • 1
  • 1

如果是行式存储,那么所有的行都会被读取,尽管只需要 price 列。如果是基于列式存储的,只需要读取 price列即可。当数据很大时,这可以有效的降低数据处理时间。

文件结构

Parquet file Format

一个Parquet file 包括一个Header,一个或者多个block,并且以Footer结尾。Header只包括4字节magic number 标明文件格式类型,文件的元数据信息存储在Footer中。元数据包括格式化version,schema,附加的key-value对,文件中每个block的元数据。

这样设计的结果就是读取Parquet文件时,首先需要寻址到文件的结尾,读取footer 元数据的长度,然后返回根据 length 读取footer 中的元数据。不像 sequenceFile、Avro 这些数据文件,它们的元数据存储在头部,并且有sync markers 可以用来分割block。Parquet 文件没有Sync maker,block的边界信息存储在footer metadata中(在写Parquet文件时,metadata是最后被写入文件的,所以在文件被关闭前block的边界位置信息都会保存在内存中)。因此Parquet文件是可切割的,在读取footer后,所有的block位置是被确定的,是能够并行处理的。

因为每个page的value都来自于相同的列,所以value都是一样的类型的,至少是相似的,这样的结果是可以是page更好的被压缩处理。

当创建文件时,Parquet会根据列的类型自动选择合适的编码。例如,boolean类型的值会使用run-length encoding 和 bit packing 编码。大多数的类型会默认使用dictionary encoding编码,如果dictionary太大的话,会使用plain编码。

Parquet 配置

block size的设置需要在读取效率和内存使用上做一个权衡。 
大的block可以是读取更加效率,然而,在读写时,每个block都会在内存中被缓存的。所以blcok不能无限大,默认是128MB。

page是Parquet最小的存储单元,随机检索一行时,page需要指定行是否被压缩和编码。所以,针对单行的查询,越小的page,越有效率。但是小的page又会造成更高的储存和处理开销,因为越多的小page,需要存储的元数据越多。默认page size 为 1MB。

局限

  1. 当写入 parquet文件时,需要很大的内存。因为需要将数据的编码和压缩信息都要缓存在内存中。所以当写如parquet文件时,要么增加heap内存,要么减小 parquet.block.size 的设置。
  2. 在使用Parquet时,如果定义了很重的嵌套的数据结构,会限制Parquet一些存储优化手段,所以,如果可能,尽可能使Schema扁平化。
  3. 在Hive中是Parquet时,还不能支持decimal 和 timestamp数据类型
  4. 在Impala中使用Parquet时,目前还不支持数据嵌套或者复杂数据类型,诸如map、structs或者arrays,据说Impala 2.x release版本会有的。
  5. Tools such as Impala work best when a Parquet file contains a single row group and when the entire file fits inside an HDFS block. In reality, it’s hard to achieve this goal when you’re writing Parquet files in systems such as MapReduce, but it’s good to keep this in mind as you’re producing Parquet files。

* 参考资料 *

  1. http://www.infoq.com/cn/articles/in-depth-analysis-of-parquet-column-storage-format
  2. OReilly.Hadoop.The.Definitive.Guide.4th.Edition
  3. Manning.Hadoop.in.Practice.2nd.Edition
 
 
posted @ 2017-03-08 22:28  XGogo  阅读(1017)  评论(0编辑  收藏  举报