Parquet列式存储格式详解,下推和压缩性能测试

摘要:列式存储Parquet

Parquet概述

Apache Parquet是面向分析型业务列式存储格式,由Twitter和Cloudera合作开发,Parquet是一种与语言无关的列式存储文件类型,可以适配多种计算框架。


列式存储和行式存储

行式存储(Row-oriented)、列式存储(Column-oriented)是两个重要的数据组织方式,列存的有parquetORC;行存的则有Avro,JSON,CSV,Text。
举例说明行式存储和列式存储的区别


在上图的music表中,如果用列存和行存存储会得到下面两种不同的组织方式。在左边的列存中,同一列的数据被组织在一起,当一列数据存储完毕时,接着下一列的数据存放,直到数据全部存好;而在行存中,数据按照行的顺序依次放置,同一行中包括了不同列的一个数据,在图中通过不同的颜色标识了数据的排列方法。

如果使用列存去处理下面的查询,可以发现它只涉及到了两列数据(album和artist),而列存中同一列的数据放在一起,那么我们就可以快速定位到所需要的列的位置,然后只读取查询中所需要的列,有效减少了无用的数据IO(year 以及 genre)。同样的,如果使用行存处理该查询就无法起到 列裁剪 的作用,因为一列中的数据被分散在文件中的各个位置,每次IO不可避免地需要读取到其他的数据,所以需要读取表中几乎所有的数据才能满足查询的条件。

列存适合处理在几个列上作分析的查询,因为可以避免读取到不需要的列数据,同时,同一列中的数据数据类型一致放置在一起也十分适合压缩。但是,如果需要对列存进行INSET INTO操作需要挪动几乎所有数据,效率十分低下。行存则只需要在文件末尾append一行数据即可。列存适合读密集的场景,特别是那些仅仅需要部分列的分析型查询;行存适合写密集的场景,或者不需要只查询某些列。


Parquet文件格式


一个Parquet文件的内容由HeaderData BlockFooter三部分组成。
Header:在文件的首尾各有一个内容为PAR1的Magic Number,用于标识这个文件为Parquet文件。Header部分就是开头的Magic Number。
Data Block:Data Block是具体存放数据的区域,由多个Row Group(行组)组成,每个Row Group包含了一批数据。比如,假设一个文件有1000行数据,按照相应大小切分成了两个Row Group,每个拥有500行数据。每个Row Group中,数据按列汇集存放,每列的所有数据组合成一个Column Chunk(列块),一个列块具有相同的数据类型,不同的列块可以使用不同的压缩。因此一个Row Group由多个Column Chunk组成,Column Chunk的个数等于列数。每个Column Chunk中,数据按照Page为最小单元来存储,根据内容分为Data PageIndex Page。这样逐层设计的目的在于:

(1)多个Row Group可以实现数据的并行
(2)不同Column Chunk用来实现列存储
(3)进一步分割成Page,可以实现更细粒度的数据访问

Footer:Footer部分由File MetadataFooter LengthMagic Number三部分组成。Footer Length是一个4字节的数据,用于标识Footer部分的大小,帮助找到Footer的起始指针位置。Magic Number同样是PAR1。File Metada包含了非常重要的信息,包括Schema每个Row Group的Metadata。每个Row Group的Metadata又由各个Column的Metadata组成,每个Column Metadata包含了其Encoding、Offset、Statistic信息等等。


Parquet存储格式举例

4-byte magic number "PAR1"
<Column 1 Chunk 1 + Column Metadata>
<Column 2 Chunk 1 + Column Metadata>
...
<Column N Chunk 1 + Column Metadata>
<Column 1 Chunk 2 + Column Metadata>
<Column 2 Chunk 2 + Column Metadata>
...
<Column N Chunk 2 + Column Metadata>
...
<Column 1 Chunk M + Column Metadata>
<Column 2 Chunk M + Column Metadata>
...
<Column N Chunk M + Column Metadata>
File Metadata
4-byte length in bytes of file metadata
4-byte magic number "PAR1"

这个表中有N列,被分成M个行组,每个行组中有N个列块。除此之外Parquet的一头一尾是header和footer,在footer中记录了file metadata


Parquet的优势

(1)列裁剪(offset of first data page -> 列的起始结束位置)

Parquet列式存储方式可以方便地在读取数据到内存之间找到真正需要的列,具体是并行的task对应一个Parquet的行组(row group),每一个task内部有多个列块,列快连续存储,同一列的数据存储在一起,任务中先去访问footer的File metadata,其中包括每个行组的metadata,里面的Column Metadata记录offset of first data pageoffset of first index page,这个记录了每个不同列的起始位置,这样就找到了需要的列的开始和结束位置。其中data和index是对数值和字符串数据的处理方式,对于字符变量会存储为key/value对的字典转化为数值

(2)谓词下推(Column Statistic -> 列的range和枚举值信息)

Parquet中File metadata记录了每一个Row group的Column statistic,包括数值列的max/min,字符串列的枚举值信息,比如如果SQL语句中对一个数值列过滤>21以上的,因此File 0的行组1和File 1的行组0不需要读取

File 0
    Row Group 0, Column Statistics -> (Min -> 20, Max -> 30)
    Row Group 1, Column Statistics -> (Min -> 10, Max -> 20)
File 1
    Row Group 0, Column Statistics -> (Min -> 6, Max -> 21)
    Row Group 1, Column Statistics -> (Min -> 25, Max -> 45)    

对于字符枚举列,先对枚举值做数值映射,如果SQL语句中要查找列中是‘leo’的数据,只需要访问File 1的行组1

File 0
    Row Group 0, Column 0 -> 0: bruce, 1:cake
    Row Group 1, Column 0 -> 0: bruce, 2:kevin
File 1
    Row Group 0, Column 0 -> 0: bruce, 1:cake, 2: kevin
    Row Group 1, Column 0 -> 0: bruce, 1:cake, 3: leo
(3)压缩效率高,占用空间少,存储成本低

Parquet这类列式存储有着更高的压缩比,相同类型的数据为一列存储在一起方便压缩,不同列可以采用不同的压缩方式,结合Parquet的嵌套数据类型,可以通过高效的编码和压缩方式降低存储空间提高IO效率


Spark操作Parquet性能测试

将一个csv格式数据上传hdfs

[root@cloudera01 pgeng]# hdfs dfs -mkdir -p /tmp/test_data.txt
[root@cloudera01 pgeng]# hdfs dfs -put -test_data.txt /tmp/test_data.txt

使用spark读取文件,再存储为parquet格式

scala> val df = spark.read.format("csv").option("sep", "\t").load("hdfs:///tmp/test_data.txt")
df: org.apache.spark.sql.DataFrame = [_c0: string, _c1: string ... 12 more fields]
scala> df.repartition(1).write.format("parquet").save("hdfs:///tmp/test_data.parquet")

查看hdfs上两个不同格式的文件目录,第一列是目标文件大小,第二列是目标文件在集群上所有副本大小综合,可见使用parquet格式文件大小较csv缩小为原来1/7

[root@cloudera01 ~]# hdfs dfs -du -h /tmp
60.6 M   181.8 M  /tmp/test_data.parquet
401.9 M  1.2 G    /tmp/test_data.txt
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350