分类目录:商业智能《数据仓库Hive编程》总目录
相关文章:
数据类型和文件格式(一):基本数据类型
数据类型和文件格式(二):集合数据类型
数据类型和文件格式(三):文本文件数据编码
数据类型和文件格式(四):读时模式
下面我们一起来研究文件格式,首先举个最简单的例子,也就是文本格式文件。毫无疑问,用户应该很熟悉以逗号或者制表符分割的文本文件,也就是所谓的逗号分隔值(CSV)或者制表符分割值(TSV)。只要用户需要,Hive是支持这些文件格式的,在后面的文章将会介绍其具体使用方式。然而,这两种文件格式有一个共同的缺点,那就是用户需要对文本文件中那些不需要作为分隔符处理的逗号或者制表符格外小心。因此,Hive默认使用了几个控制字符,这些字符很少出现在字段值中。Hive 使用术语field
来表示替换默认分隔符的字符。
分隔符 | 描述 |
---|---|
\n | 对于文本文件来说,每行都是一条记录,因此换行符可以分割记录 |
^A(Ctrl+A) | 用于分隔字段(列)。在CREATE TABLE 语句中可以使用八进制编码\001表示 |
^B | 用于分隔ARRARY 或者STRUCT 中的元素,或用于MAP 中键值对之间的分隔。在CREATE TABLE 语句中可以使用八进制编码\002表示 |
^C | 用于MAP 中键和值之间的分隔。在CREATE TABLE 语句中可以使用八进制编码\003表示 |
前面章节中介绍的employees
表的记录看上去和下面展示的这个例子是一样的,其中使用到了^A
等字符来作为字段分隔符。像Emacs这样的文本编辑器将会以这种形式来展示这些分隔符。因为页面篇幅有限,所以每行数据并非显示在同一行。为了能较清晰地展示每行记录,我们在行与行间额外增加了一个空行:
John Doe^A100000.0^AMary Smith^BTodd Jones^AFederal Taxes^C.2^BStateTaxes^C.05^ BInsurance^C.1^A1 Michigan Ave.^BChicago^BIL^B60600
Mary Smith^A80000.0^ABill King^AFederal Taxes^C.2^BState Taxes^C.05^BInsurance^ C.1^A100 Ontario St.^BChicago^BIL^B60601
Todd Jones^A70000.0^AFederal Taxes^C.15^BState Taxes^C.03^BInsurance^C.1^A200 Chicago Ave.^BOak Park^BIL^B60700
Bill King^A60000.0^AFederal Taxes^C.15^BState Taxes^C.03^BInsurance^C.1^A300 Obscure Dr.^BObscuria^BIL^B60100
其可读性并不好,但是我们可以使用Hive来读取这些数据。我们先来看看第1行记录来了解一下这个结构。首先,如果使用JavaScript数据交换格式(JSON)来表示这条记录的话,那么如果增加了额表结构中的字段名称的话,样式将会和如下所示的一样:
{
"name": "John Doe",
"salary": 100000.0,
"subordinates": ["Mary Smith", "Todd Jones"],
"deductions": {
"Federal Taxes": .2,
"State Taxes": .05,
"Insurance": .1
},
"address": {
"street": "1 Michigan Ave.",
"city": "Chicago",
"state": "IL",
"zip": 60600
}
}
这里,用户可能会发现在JSON中map
类型和struct
类型其实是一样的。那么,我们来看看文本文件的第1行分解出来的结果:
① “John Doe”对应name
字段,表示用户名。
② “100000.0”对应salary
字段,表示薪水。
③ “Mary Smith^BTodd Jones” 对应subordinates
字段,表示下属是“Mary Smith”和“Todd Jones”。
④ “Federal Taxes”、“BState Taxes”、“BInsurance”对应deductions
字段,表示扣除的金额,其中20%用于上缴“国税”,5%用于上缴“州税”,还有10%用于上缴“保险费。”
⑤ “1 Michigan Ave. Chicago”对应address
字段,表示住址是“芝加哥第一密歇根大道60600号”。
用户可以不使用这些默认的分隔符,而指定使用其他分隔符。当有其他应用程序使用不同的规则写数据时,这是非常必要的。下面这个表结构声明和之前的那个表是一样的,不过这里明确地指定了分隔符:
CREATE TABLE employees (
name STRING,
salary FLOAT,
subordinates ARRAY,
deductions MAP,
address STRUCT
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001'
COLLECTION ITEMS TERMINATED BY '\002'
MAP KEYS TERMINATED BY '\003'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
ROW FORMAT DELIMITED
这组关键字必须要写在其他子句(除了STORED AS ...
子句)之前。
字符\001
是^A
的八进制数。ROW FORMAT DELIMITED FIELDS TERMINATED BY '\001'
这个子句表明Hive将使用^A
字符作为列分割符。
同样地,字符\002
是^B
的八进制数。ROW FORMAT DELIMITED COLLECTION ITEMS TERMINATED BY '\002'
这个子句表明Hive将使用^B
作为集合元素间的分隔符。
最后,字符\003
是^C
的八进制数。ROW FORMAT DELIMITED MAP KEYS TERMINATED BY '\003'
这个子句表明Hive将使用^C
作为map
的键和值之间的分隔符。子句LINES TERMINATED BY '…'
和STORED AS …
不需要ROW FORMAT DELIMITED
关键字。
事实上,Hive到目前为止对于LINESTERMINATED BY …
仅支持字符\n
,也就是说行与行之间的分隔符只能为\n
。因此这个子句现在使用起来还是有限制的。
用户可以重新指定列分割符及集合元素间分隔符,而map
中键值间分隔符仍然使用默认的文本文件格式,因此子句STORED AS TEXTFILE
很少被使用到。
因此,虽然用户可以明确指定这些子句,但是在大多数情况下,大多子句还是使用默认的分割符的,只需要明确指定那些需要替换的分隔符即可。
当然,这些规则只会影响到Hive在读取文件后将如何进行划分。只有在一些比较极端的情况下,才需要用户手工去将数据按正确的格式写入文件。
例如,如下表结构声明定义的是一个表数据按照逗号进行分割的表。
CREATE TABLE some_data (
first FLOAT,
second FLOAT,
third FLOAT
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ',';
用户还可以使用\t
(制表符)作为字段分隔符。这种强大的可定制功能使得可以很容易地使用Hive来处理那些由其他工具和各种各样的ETL(也就是数据抽取、数据转换和数据装载过程)程序产生的文件。