整套大数据学习资料(视频+笔记)百度网盘无门槛下载:http://www.edu360.cn/news/content?id=3377

12.6.3 存储格式

hadoop 小红牛 12℃ 0评论

Hive从两个维度对表的存储进行管理:“行格式”(row
format)和“文件格 式”(file format)。行格式指行和一行中的字段如何存储。按照Hive的术
语,行格式的定义由SerDe定义。SerDe是“序列化和反序列化工具” (Serializer-Deserializer)的合成词。

当作为反序列化工具进行使用时——也就是査询表时——SerDe将把文件中
字节形式的数据行反序列化为Hive内部操作数据行时所使用的对象形式。
使用序列化工具时——也就是执行INSERT或CTAS(参见12.6.4节)时一表
的SerDe会把Hive的数据行内部表示形式序列化成字节形式并写到输出文 件中。

文件格式指一行中字段容器的格式。最简单的格式是纯文本文件,但是也 可以使用面向行的和面向列的二进制格式。

1.默认存储格式:分隔的文本如果在创建表时没有用ROW FORMAT或STORED AS子句,那么Hive所使用 的默认格式是分隔的文本(delimited text),每行(line)存储一个数据行(row)。

默认的行内分隔符不是制表符,而是ASCII控制码集合中的Control-A(它
的ASCII码为1)。选择Contml-A(在文档中有时记作"A)作为分隔符是因为
和制表符相比,它出现在字段文本中的可能性比较小。在Hive中无法对分 隔符进行转义,因此,挑选一个不会在数据字段中用到的字符作为分隔符
非常重要。

“集合”(collection)元素的默认分隔符为字符Control-B。它用于分隔 ARRAY或STRUCT或MAP的键/值对中的元素。默认的映射键(map key)分隔符为 字符Control-C。它用于分隔MAP的键和值。表中各行之间用换行符分隔。

前面对分隔符的描述对一般情况下的平面数据结构——即只包含原子数据类型的复杂数据类型—都是没有问题的。但是,对于嵌套数据 类型,这还不够。事实上,嵌套的层次(level)决定了使用哪种分隔符。

例如,对于数组的数组,外层数组的分隔符如前所述是Control-B字 符,但内层数组则使用分隔符列表中的下一项(Control-C字符)作为分隔符。如果不确定Hive使用哪个字符作为某个嵌套结构的分隔 符,可以运行下面的命令:

CREATE TABLE nested 
AS
SELECT array(array(l, 2), array(3, 4))
FROM dummy;

然后再使用hexdump或类似的命令来査看输出文件的分隔符。

实际上,Hive支持8级分隔符,分别对应于ASCII编码的1, 2,……,8。但是你只能重载其中的前三个。

因此,以下语句:

CREATE TABLE …;

等价于下面显式说明的语句:

CREATE TABLE ...
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001'
COLLECTION ITEMS TERMINATED BY '\002'
MAP KEYS TERMINATED BY '\003'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

注意,我们可以使用八进制形式来表示分隔符—例如,001表示Control-A。

Hive在内部使用一个名为LazySimpleSerDe的SerDe来处理这种分隔格
式以及我们在第7章看到的面向行的MapReduce文本输入和输出格式。这
里使用前缀“lazy”的原因是这个SerDe对字段的反序列化是延迟处理的一 一只有在访问字段时才进行反序列化。但是,由于文本以冗长的形式进行
存放,所以这种存储格式并不紧凑。比如,一个布尔值事实上是以文本 字符串true或false的形式存放的。

这种简单的格式有很多好处,例如,使用其他工具(包括MapReduce程序或 Streaming)来处理这样的格式非常容易。但是还可以选择一些更紧凑和髙效 的二进制SerDe。表12-4列出了一部分可用的SerDe。

二进制SerDe不应该和默认的TEXTFILE格式(或显式的STORED AS TEXTFILE子句)一起使用。二进制数据行中几乎总是包含换行符, 这会导致Hive把行截断,从而在反序列化时失败。

表 12-4. Hive 的 SerDe

SerDe名称

Java 包

描述

LazySimpleSerDe

org.apache.hadoop.hive. serde2.lazy

这是默认的SerDe。采用分 隔的文本格式和延迟的字段 访问

LazyBinarySerDe

org.apache.hadoop.hive. serde2.lazybinary

LazySimpleSerDe 的一个更高效的实现。二进制形式的 延迟字段访问。供临时表这 样的表内部使用

BinarySortableSerDe

org.apache.hadoop.hive. serde2.binarysortable

类似于 LazyBinarySerDe 的 二进制SerDe,但它针对排序进 行了优化,损失了部分空间(但仍 然比 LazySimpleSerDe 精简

很多)

ColumnarSerDe

org.apache.hadoop. hive.serde2.columnar

针对RCFile格式的基于列存 储的 LazySimpleSerDe 变种

RegexSerDe

org.apache.hadoop. hive.contrib.serde2

一种根据用正则表达式给出 的列读取文本数据的 SerDe。它也能使用格式表达 式写入数据。对于读取日志 文件有用。它的效率不高, 因此不适合普通的存储

ThriftByteStreamTypedSerDe

org. apache. hadoop.hive.serde2.thrift

读取Thrift编码的二进制数据 的 SerDe

2.二进制存储格式:顺序文件、Avro数据文件以及RCFile

Hadoop的顺序文件格式(参见4.5.1)是一种针对顺序和记录(/值对)的通 用二进制格式。在Hive中,可以在CREATE TABLE语句中通过声明 STORED AS SEQUENCEFILE来使用顺序文件。

使用序列文件的一个主要的优点是它们支持可分割(splittable)的压缩。如果 你有一系列在Hive外创建的序列文件,则无须额外设置,Hive也能读取它 们。另一方面,如果你想使用压缩顺序文件来存储Hive产生的表,则需要 设置几个相应的属性来使用压缩(参见4.2.3节):

hive> CREATE TABLE compressed__users (id INT, name STRING)
>STORED AS SEQUENCEFILE;
hive> SET hive.exec.compress.output=true;
hive> SET mapred.output.compress=true;
hive> SET mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec; 
hive> INSERT OVERWRITE TABLE compressed__users
>SELECT * FROM users;

顺序文件是面向行的。这意味着同一行中的字段作为顺序文件中的一条记 录被存储在一起。

Avro数据文件和顺序文件相似:可分割、可压缩、面向行。不同点是,
Avro数据文件支持模式演化以及多种编程语言的绑定(参见4.4节)。Hive 可以使用Wajvvreo
SerDe读取或写入Avro数据文件。Haivvreo SerDe可从 http://github.com/jghoman/haivvreo
获得。

Hive提供了另一种二进制存储格式,称为RCFile,表示按列记录文件
(Record Columnar File)。RCFile除了按列的方式存储数据以外,其他方面
都和序列文件类似。RCFile把表分成行分片(row split),在每一个分片中先
存所有行的第一列,再存它们的第二列,依此类推。图12-3用图示说明了 这种存储方式。

面向列的存储布局(colunm-oriented
layout)方式可以使一个査询跳过那些不 必访问的列。让我们考虑一个只需要处理图12-3中表的第2列的査询。在
像顺序文件这样面向行的存储中,即使其实只需要读取第二列,整个数据 行(存储在顺序文件的一条记录中)也都会被加载到内存中。虽说在某种程度
上“迟反序列化”(lazy deserialization)策略通过只反序列化那些被访问的列
字段能节省一些处理开销,但这仍然不能避免从磁盘读入一个数据行所有 字节而额外付出的开销。

如果使用面向列的存储,只需要把文件中第2列所对应的那部分(图中的阴 影部分)读入内存。

图片.png 

图12-3.面向行的和面向列的存储

一般来说,面向列的存储格式对于那些只访问表中一小部分行的查询比较 有效。相反,面向行的存储格式适合同时处理一行中很多列的情况。如果 存储空间足够,可以使用12.6.4节的CREATE TABLE…AS SELECT子句来 复制一个表,创建它的另一种储格式,从而直观地比较査询负载下两种 存储格式在性能上的差异。

在Hive中,可以使用如下的CREATE TABLE子句来启用面向列的存储:

CREATE TABLE …
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.columnar.ColumnarSerDe'
 STORED AS RCFILE;

3.示例:RegexSerDe

现在让我们看看如何使用另一种SerDe来进行存储。我们将使用一个用户 贡献的SerDe,它采用一个正则表达式从一个文本文件中读取定长的观测站

元数据:

CREATE TABLE stations (usaf STRING, wban STRING, name STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input, regex" = n(\\d{6}) (\\d{5}) (.{29}) .*”
);

在前面的示例中,我们在ROW
FORMAT子句中使用DELIMITED关键字来说 明文本是如何分隔的。在这个示例中,我们用另一种方式,用SERDE关键
字和实现SerDe的Java类的完整类名(即org.apache.hadoop.hive.colrtrib.serde2.RegexSer'De),
来指明使用哪个 SerDe。

SerDe可以用WITH SERDEPROPERTIES子句考设置额外的属性。在这里, 我们要设置RegexSerDe特有的input, regex属性。

input,
regex是在反序列化期间将要使用的正则表达式模式,用来将数据 行(row)中的部分文本转化为列的集合。正则表达式匹配时使用java的正则
轰ih式语法(参见
http://java.sm.eom/javase/6/docs/api/java/util/fegex/Pattern.html)。教
们通过识别一组一组的括号来确定列(称为捕获组,即capturing group)。®
在这个示例中,有三个捕获组:usaf(六位数的标识符)、wban(五位数的标 识符)以及name(29个字符的定长列)。

我们像以前一样,用如下LOAD DATA语句向表中输入数据:

LOAD DATA LOCAL INPATH ”input/ncdc/metadata/stations-fixed-width.txt’J INTO TABLE stations;

回想一下,LOAD DATA把文件复制或移动到Hive的仓库目录中。在这里, 由于源在本地文件系统中,所以使用的是复制操作。加载操作并不使用表 的 SerDe。

从文件中检索数据时,如下面这个简单査询所示,反序列化会调用SerDe, 从而使每一行的字段都能被正确解析出来:

hive> SELECT * FROM stations LIMIT 4;
10000 99999 BOGUS NORWAY
 
010003 99999 BOGUS NORWAY
010010 99999 DAN MAYEN
010013 99999 ROST

转载请注明:全栈大数据 » 12.6.3 存储格式

喜欢 (0)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址