Apache Hive支持Apache Hadoop中使用的几种熟悉的文件格式,如TextFile,RCFile,SequenceFile,AVRO,ORC和Parquet格式。Cloudera Impala也支持这些文件格式。 在建表时使用STORED AS (TextFile|RCFile|SequenceFile|AVRO|ORC|Parquet)来指定存储格式。
TextFile每一行都是一条记录,每行都以换行符(\ n)结尾。数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
SequenceFile是Hadoop API提供的一种二进制文件支持,其具有使用方便、可分割、可压缩的特点。支持三种压缩选择:NONE, RECORD, BLOCK。 Record压缩率低,一般建议使用BLOCK压缩。
RCFile是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。
AVRO是开源项目,为Hadoop提供数据序列化和数据交换服务。您可以在Hadoop生态系统和以任何编程语言编写的程序之间交换数据。Avro是基于大数据Hadoop的应用程序中流行的文件格式之一。
ORC文件代表了优化排柱状的文件格式。ORC文件格式提供了一种将数据存储在Hive表中的高效方法。这个文件系统实际上是为了克服其他Hive文件格式的限制而设计的。Hive从大型表读取,写入和处理数据时,使用ORC文件可以提高性能。
Parquet是一个面向列的二进制文件格式。Parquet对于大型查询的类型是高效的。对于扫描特定表格中的特定列的查询,Parquet特别有用。Parquet桌子使用压缩Snappy,gzip;目前Snappy默认。
1 概述
官方链接:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-StorageFormatsStorageFormatsRowFormat,StorageFormat,andSerDe
上一篇博客我们详细的介绍了压缩的使用,本文将详细介绍Hive中的存储格式,下面列出官方给出的存储格式:
[STORED AS file_format]
file_format:
: SEQUENCEFILE
| TEXTFILE -- (Default, depending on hive.default.fileformat configuration)
| RCFILE -- (Note: Available in Hive 0.6.0 and later)
| ORC -- (Note: Available in Hive 0.11.0 and later)
| PARQUET -- (Note: Available in Hive 0.13.0 and later)
| AVRO -- (Note: Available in Hive 0.14.0 and later)
| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
TEXTFILE是默认的存储格式,下面进行详细的介绍几种常用的存储格式。
2 TEXTFILE:文本文件
- 存储方式:行存储;
- 默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
创建一张tt表进行分析
CREATE TABLE tt (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
查看tt表格信息
desc formatted tt
# Storage Information
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: No
Num Buckets: -1
Bucket Columns: []
Sort Columns: []
Storage Desc Params:
field.delim \t
serialization.format \t
这两种方式也是创建TEXTFILE的存储格式:
方式一:
CREATE TABLE tt2 (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS TEXTFILE;
方式二:
CREATE TABLE tt3 (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS
INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat';
3 Sequencefile:二进制文件
Record:存储SequenceFile通用的KV数据格式,Key和Value都是二进制变长的数据。Record表示Key和Value的byte的总和。
Sync:主要是用来扫描和恢复数据的,以至于读取数据的Reader不会迷失。
Header:存储了如下信息:文件标识符SEQ,key和value的格式说明,以及压缩的相关信息,metadata等信息。
metadata:包含文件头所需要的数据:文件标识、Sync标识、数据格式说明(含压缩)、文件元数据(时间、owner、权限等)、检验信息等。
存储方式:行存储;
- SequenceFile是Hadoop API 提供的一种二进制文件,它将数据(key,value)的形式序列化到文件里。这样的二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。
- Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,只是它的key为空。使用value 存放实际的值。 这样是为了避免MR 在执行map 阶段的排序过程。
- SEQUENCEFILE比TextFile 多了一些冗余信息,所以要大一些。
创建page_views_seq表
create table page_views_seq(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS SEQUENCEFILE;
这时候并不能使用load将数据加载到存储格式为SEQUENCEFILE的表中,需要先创建TextFile的存储格式的表中,然后insert into到存储格式为SEQUENCEFILE的表中。
插入数据:insert into table page_views_seq select * from page_views;
数据大小对比:
TextFile存储格式的大小
[hadoop@hadoop ~]$ hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views
18.1 M /user/hive/warehouse/hive.db/page_views
SEQUENCEFILE存储格式的大小
[hadoop@hadoop ~]$ hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views_seq
19.6 M /user/hive/warehouse/hive.db/page_views_seq
原始大小
[hadoop@hadoop ~]$ du -sh data/page_views.dat
19M data/page_views.dat
4 Rcfile
1. 这个架构是利用了先行式存储再列式存储的方式。在每个row group中为列式存储,相对于sequenceFile的大小,有一定优势,大概比textFile小10%。
2. 当查询过程中,针对它并不关心的列时,它会在IO上跳过这些列。须要说明的是。RCFile在map阶段从远端拷贝仍然是拷贝整个数据块,而且复制到本地文件夹后,RCFile并非真正直接跳过不须要的列,并跳到须要读取的列, 而是通过扫描每个row group的头部定义来实现的。
可是在整个HDFS Block 级别的头部并未定义每个列从哪个row group起始到哪个row group结束。所以在读取全部列的情况下。RCFile的性能反而没有SequenceFile高。
创建page_views_seq表
create table page_views_rcfile(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS RCFILE;
插入数据:
insert into table page_views_rcfile select * from page_views;
查看大小:
hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views_rcfile
17.9 M /user/hive/warehouse/hive.db/page_views_rcfile
5 ORC
官方网站
ORC的全称是(Optimized Row Columnar),ORC文件格式是一种Hadoop生态圈中的列式存储格式,它的产生早在2013年初,最初产生自Apache Hive,用于降低Hadoop数据存储空间和加速Hive查询速度。和Parquet类似,它并不是一个单纯的列式存储格式,仍然是首先根据行组分割整个表,在每一个行组内进行按列存储。ORC文件是自描述的,它的元数据使用Protocol Buffers序列化,并且文件中的数据尽可能的压缩以降低存储空间的消耗,目前也被Spark SQL、Presto等查询引擎支持,但是Impala对于ORC目前没有支持,仍然使用Parquet作为主要的列式存储格式。2015年ORC项目被Apache项目基金会提升为Apache顶级项目。ORC具有以下一些优势:
1. ORC是列式存储,有多种文件压缩方式,并且有着很高的压缩比。
2. 文件是可切分(Split)的。因此,在Hive中使用ORC作为表的文件存储格式,不仅节省HDFS存储资源,查询任务的输入数据量减少,使用的MapTask也就减少了。
3. 提供了多种索引,row group index、bloom filter index。
4. ORC可以支持复杂的数据结构(比如Map等)
和Parquet类似,ORC文件也是以二进制方式存储的,所以是不可以直接读取,ORC文件也是自解析的,它包含许多的元数据,这些元数据都是同构ProtoBuffer进行序列化的。ORC的文件结构如下图:
ORC文件:保存在文件系统上的普通二进制文件,一个ORC文件中可以包含多个stripe,每一个stripe包含多条记录,这些记录按照列进行独立存储,对应到Parquet中的row group的概念。
文件级元数据:包括文件的描述信息PostScript、文件meta信息(包括整个文件的统计信息)、所有stripe的信息和文件schema信息。
stripe:一组行形成一个stripe,每次读取文件是以行组为单位的,一般为HDFS的块大小,保存了每一列的索引和数据。
stripe元数据:保存stripe的位置、每一个列的在该stripe的统计信息以及所有的stream类型和位置。
row group:索引的最小单位,一个stripe中包含多个row group,默认为10000个值组成。
stream:一个stream表示文件中一段有效的数据,包括索引和数据两类。索引stream保存每一个row group的位置和统计信息,数据stream包括多种类型的数据,具体需要哪几种是由该列类型和编码方式决定。
- 读取ORC文件是从尾部开始的,第一次读取16KB的大小,尽可能的将Postscript和Footer数据都读入内存。文件的最后一个字节保存着PostScript的长度,它的长度不会超过256字节,PostScript中保存着整个文件的元数据信息,它包括文件的压缩格式、文件内部每一个压缩块的最大长度(每次分配内存的大小)、Footer长度,以及一些版本信息。在Postscript和Footer之间存储着整个文件的统计信息(上图中未画出),这部分的统计信息包括每一个stripe中每一列的信息,主要统计成员数、最大值、最小值、是否有空值等。
- 接下来读取文件的Footer信息,它包含了每一个stripe的长度和偏移量,该文件的schema信息(将schema树按照schema中的编号保存在数组中)、整个文件的统计信息以及每一个row group的行数。
- 处理stripe时首先从Footer中获取每一个stripe的其实位置和长度、每一个stripe的Footer数据(元数据,记录了index和data的的长度),整个striper被分为index和data两部分,stripe内部是按照row group进行分块的(每一个row group中多少条记录在文件的Footer中存储),row group内部按列存储。每一个row group由多个stream保存数据和索引信息。每一个stream的数据会根据该列的类型使用特定的压缩算法保存。
在建Hive表的时候我们就应该指定文件的存储格式。所以你可以在Hive QL语句里面指定用ORCFile这种文件格式,如下:
CREATE TABLE ... STORED AS ORC
ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT ORC
SET hive.default.fileformat=Orc
所有关于ORCFile的参数都是在Hive QL语句的TBLPROPERTIES字段里面出现,他们是:
总结: ORC能很大程序的节省存储和计算资源,但它在读写时候需要消耗额外的CPU资源来压缩和解压缩,当然这部分的CPU消耗是非常少的。
对性能提升的另一个方面是通过在ORC文件中为每一个字段建立一个轻量级的索引,来判定一个文件中是否满足WHERE子句中的过滤条件。比如:当执行HQL语句”SELECT COUNT(1) FROM lxw1234_orc WHERE id = 0”时候,先从ORC文件的metadata中读取索引信息,快速定位到id=0所在的offsets,如果从索引信息中没有发现id=0的信息,则直接跳过该文件。
存储格式 | 存储方式 | 特点 |
---|---|---|
TextFile | 行存储 | 存储空间消耗比较大,并且压缩的text 无法分割和合并 查询的效率最低,可以直接存储,加载数据的速度最高 |
SequenceFile | 行存储 | 存储空间消耗最大,压缩的文件可以分割和合并 查询效率高,需要通过text文件转化来加载 |
RCFile | 数据按行分块 每块按照列存储 | 存储空间最小, 查询的效率最高 , 需要通过text文件转化来加载, 加载的速度最低。 压缩快 快速列存取。 读记录尽量涉及到的block最少 读取需要的列只需要读取每个row group 的头部定义。 读取全量数据的操作 性能可能比sequencefile没有明显的优势 |
ORCFile | 数据按行分块 每块按照列存储 | 压缩快,快速列存取 ,效率比rcfile高,是rcfile的改良版本 |
Parquet | 列存储 | 相对于PRC,Parquet压缩比较低,查询效率较低,不支持update、insert和ACID.但是Parquet支持Impala查询引擎 |
Parquet http://parquet.apache.org | Orc http://orc.apache.org | |
---|---|---|
发展状态 | 目前都是Apache开源的顶级项目,列式存储引擎 | 目前都是Apache开源的顶级项目,列式存储引擎 |
开发语言 | Java | Java |
主导公司 | Twitter/Cloudera | Hortonworks |
ACID | 不支持 | 支持ACID事务 |
修改操作(update,delete) | 不支持 | 支持 |
支持索引(统计信息) | 粗粒度索引 block/group/chunk级别统计信息 | 粗粒度索引 file/stripe/row级别统计信息, 不能精确到列建立索引 |
支持的查询引擎 | Apache Drill、Impala | Apache Hive |
查询性能 | Orc性能更高一点 | Orc性能更高一点 |
压缩比 | Orc压缩比更高(见下图) | Orc压缩比更高(见下图) |
列编码 | 支持多种编码,字典,RLE,Delta等 | 支持主流编码,与Parquet类似 |
总结:如果仅仅是在HIve中存储和查询,建议使用ORC格式,如果在Hive中存储,而使用Impala查询,建议使用Parquet。
参考资料: