当前位置: > > > Hive - 数据存储格式详解6(PARQUET格式)

Hive - 数据存储格式详解6(PARQUET格式)

六、PARQUET 格式

1,基本介绍

(1)Parquet 是一种新型的与语言无关的,并且不和任何一种数据处理框架绑定的列式存储结构,适配多种语言和组件。Parquet 数据存储格式可以在 HiveImpalaSpark 等计算引擎中使用。

(2)Parquet 的存储格式如下图所示:
  • Parquet 格式的文件中包含了多个 Row Group
  • 每个 Row Group 内部包含了多个 Column
  • Column 内部包含了多个 Page
  • Page 内部存储了具体的数据内容。

(3)上面图看起来稍微有点复杂,简化一下就是下面这样的:
  • 可以看出 Parquet 存储格式比 ORC 更复杂一些,多封装出来一层 PageORC 存储格式是把数据内容直接存储到了 Column 这一层。

(4)在创建 PARQUET 数据存储格式表的时候,和 ORC 格式一样,所有关于 PARQUET 的参数都在建表语句中的 tblproperties 中指定,不需要在 hive 的命令行中使用 set 命令指定了。
注意tblproperties 中可以指定多个参数,多个参数之间使用逗号分割即可。
create table t1(
  id int,
  name string
) stored as parquet tblproperties("parquet.compression"="uncompressed")

(5)目前 PARQUET 支持 uncompressedsnappygzip or lzobrotlilz4zst 这几种压缩格式。默认是 uncompressed

2,不使用压缩

(1)首先我们执行如下命令在 Hive 创建一个 PARQUET 存储格式的表,不使用压缩。
注意
  • 这里需要在 stored as 后面指定 parquet,并且在 tblproperties 中指定 "parquet.compression"="uncompressed"
  • 针对 PARQUET 存储格式的表在控制压缩格式的时候是通过 parquet.compression 指定的,不需要在 hive 中设置 hive.exec.compress.output 参数了。
create external table stu_parquet_none_compress(
  id int,
  name string,
  city string
)
row format delimited
fields terminated by ','
lines terminated by '\n'
stored as parquet
location '/stu_parquet_none_compress'
tblproperties("parquet.compression"="uncompressed");

(2)创建后执行如下命令确认一下这个表,如果 INPUTFORMAT 使用的是 MapredParquetInputFormat,说明这个表中需要存储 PARQUET 格式的数据。
show create table stu_parquet_none_compress;

(3)然后从普通表中查询数据导入到这个 PARQUET 存储格式的表中。
  • 在这里我们设置 mapreduce.job.reduces=1,表示将结果数据写入到一个数据文件中,这也便于后面验证这个数据文件是否支持 Split
普通表 stu_textfile 中的数据来源可以参考我前面写的文章:Hive - 数据存储格式详解 2(TextFile 格式)
set mapreduce.job.reduces=1;
insert into stu_parquet_none_compress select id,name,city from stu_textfile group by id,name,city;
  • 如果在任务执行过程中,特别是 reduce 阶段报“Caused by: java.lang.OutOfMemoryError: Java heap space”内存溢出错误,可以在命令执行前通过 set 命令调整内存限制,提高可用的内存大小:
set mapreduce.map.memory.mb=4096;
set mapreduce.map.java.opts=-Xmx4096m;
set mapreduce.reduce.memory.mb=4096;
set mapreduce.reduce.java.opts=-Xmx4096m;

(4)查看结果数据可以发现,其体积为 1G,远小于原始的 TextFile 文件以及 SequenceFile 格式的 2G 大小,可以说明 PARQUET 在数据存储层面还是比较优秀的。

(5)接下来写一个 sql 查询表中的数据,验证是否支持切分:
select id,count(*) from stu_parquet_none_compress group by id;
  • 可以看到产生了 8map 任务,说明 PARQUET 格式的文件是支持切分的。

(6)最后,这个表中的数据验证完毕之后,建议删除一下数据,释放 HDFS 空间。
hdfs dfs -rm -r -skipTrash /stu_parquet_none_compress

3,使用 Gzip 压缩

(1)接下来我们构建一个新的压缩数据表,指定 Gzip 压缩格式。
create external table stu_parquet_gzip_compress(
  id int,
  name string,
  city string
)
row format delimited
fields terminated by ','
lines terminated by '\n'
stored as parquet
location '/stu_parquet_gzip_compress'
tblproperties("parquet.compression"="gzip");

(2)接下来通过 insert into select 从普通表中查询数据,插入到压缩表中。
  • 在这里我们设置 mapreduce.job.reduces=1,表示将结果数据写入到一个数据文件中,这也便于后面验证这个数据文件是否支持 Split
注意:为了能够控制任务最终产生的数据文件个数,在这里通过 mapreduce.job.reduces 来控制,并且 SQL 语句中需要有可以产生 shuffle 的操作,如果是普通的 select 语句,最终是不会产生 Reduce 任务的,那么 mapreduce.job.reduces 这个参数就无法生效了。
set mapreduce.job.reduces=1;
insert into stu_parquet_gzip_compress select id,name,city from stu_textfile group by id,name,city;
  • 如果在任务执行过程中,特别是 reduce 阶段报“Caused by: java.lang.OutOfMemoryError: Java heap space”内存溢出错误,可以在命令执行前通过 set 命令调整内存限制,提高可用的内存大小:
set mapreduce.map.memory.mb=4096;
set mapreduce.map.java.opts=-Xmx4096m;
set mapreduce.reduce.memory.mb=4096;
set mapreduce.reduce.java.opts=-Xmx4096m;
  • 可以看到最终产生的数据文件大小为 318M

(3)接下来写一个 sql 查询压缩表中的数据,确认一下是否验证是否支持切分:
select id,count(*) from stu_parquet_gzip_compress group by id;
  • 结果发现只产生了 2Map 任务,说明说明 Parquet 格式带压缩的文件也支持切分。

(6)最后,这个压缩表中的数据查看后最好删除一下,这样可以释放 HDFS 存储空间。
hdfs dfs -rm -r -skipTrash /stu_parquet_gzip_compress

4,使用 Snappy 压缩

(1)接下来我们构建一个新的压缩数据表,指定 Snappy 压缩格式。
create external table stu_parquet_snappy_compress(
  id int,
  name string,
  city string
)
row format delimited
fields terminated by ','
lines terminated by '\n'
stored as parquet
location '/stu_parquet_snappy_compress'
tblproperties("parquet.compression"="snappy");

(2)接下来通过 insert into select 从普通表中查询数据,插入到压缩表中。
  • 在这里我们设置 mapreduce.job.reduces=1,表示将结果数据写入到一个数据文件中,这也便于后面验证这个数据文件是否支持 Split
注意:为了能够控制任务最终产生的数据文件个数,在这里通过 mapreduce.job.reduces 来控制,并且 SQL 语句中需要有可以产生 shuffle 的操作,如果是普通的 select 语句,最终是不会产生 Reduce 任务的,那么 mapreduce.job.reduces 这个参数就无法生效了。
set mapreduce.job.reduces=1;
insert into stu_parquet_snappy_compress select id,name,city from stu_textfile group by id,name,city;
  • 如果在任务执行过程中,特别是 reduce 阶段报“Caused by: java.lang.OutOfMemoryError: Java heap space”内存溢出错误,可以在命令执行前通过 set 命令调整内存限制,提高可用的内存大小:
set mapreduce.map.memory.mb=4096;
set mapreduce.map.java.opts=-Xmx4096m;
set mapreduce.reduce.memory.mb=4096;
set mapreduce.reduce.java.opts=-Xmx4096m;
  • 此时发现结果数据文件有 701M。比 Gzip 的压缩性能差一些,因为 Gzip 的压缩比确实比 Snappy 高,Snappy 最主要的优点是压缩和解压速度快。

(3)接下来写一个 sql 查询压缩表中的数据,确认一下是否验证是否支持切分:
select id,count(*) from stu_parquet_snappy_compress group by id;
  • 结果发现产生了 3Map 任务,说明 PARQUET + Snappy 压缩的文件也支持切分。

(4)最后,这个压缩表中的数据查看后最好删除一下,这样可以释放 HDFS 存储空间。
hdfs dfs -rm -r -skipTrash /stu_parquet_snappy_compress
评论0