Hive支持关系型数据库的大多数基本数据类型,同时也支持关系型数据库中很少出现的3种集合数据类型
为什么这么做?
- 考虑因素一:数据类型是如何在文本中进行表示
- 考虑因素二:文本存储中为了解决各种性能问题以及其他问题有哪些替代方案
基本数据类型
数据类型 | 长度 | 例子 |
---|---|---|
TINYINT | 1byte有符号整数 | 20 |
SMALINT | 2byte有符号整数 | 20 |
INT | 4byte有符号整数 | 20 |
BIGYINT | 8byte有符号整数 | 20 |
BOOLEAN | 布尔类型true或false | TRUE |
FLOAT | 单精度浮点 | 3.14159 |
DOUBLE | 双精度浮点 | 3.14159 |
STRING | 字符序列,可以指定字符集。可以使用单引号或双引号 | 'string',"string" |
TIMESTAMP | 整数,浮点或者字符串 | JDBC所兼容的时间格式 |
BINARY | 字节数组 | 参考后面内容 |
所有的这些数据类型都是对Java中的接口实现,因此这些数据类型具体行为细节和Java中对应的数据类型是完全一致的。
如果用户在查询中将一个float和double进行比较,Hive会隐式地将类型转换为两个值中较大的类型,也就是把float转为double。
用户也可以显示地将一种数据类型转为其他一种数据类型,如:s = “1”,需要把s转为int则可以用
cast ( s as int)
as 和 int 是关键字,大小写都可以
集合数据类型
数据类型 | 描述 | 字面语法示例 |
---|---|---|
STRUCT | 和C语言中的stuct或者'对象'类似,都可以通过“点”符号访问元素内容。例如,如果某个列的元素类型是STRUCT{fisrt STRING,last STRING},那么第一个元素可以通过,字段名.first来引用 | struct('John','Doe') |
MAP | MAP是一组键值对元组集合,使用数组表示法(例如['key'])可以访问元素。例如,某个列的数据类型是MAP,其中键->值对是'fisrt' -> 'John'和'last' -> 'Doe',那么可以通过字段名['last']获取最后一个元素 | map('fisrt':'John','last':'Doe') |
ARRAY | 数组是一组具有相同类型和名称的变量集合。这些变量称为数组元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为['John','Doe'],那么第二个数组值可以用过数组名[1]进行引用 | Array('John','Doe') |
大多数的关系型数据库并不支持这些集合数据类型,因为使用它们会趋向于破坏标准格式。破坏标准带来的问题是会增大数据冗余风险,进而导致不必要的磁盘空间,还有可能造成数据不一致,因为当数据发生改变时冗余的拷贝数据可能无法进行相应的同步
这里有一个用于演示如何使用这些数据类型的表结构声明语句,这是一张虚拟的人力资源应用程序的员工表
CREATE TABLE employees(
name STRING,
salary FLOAT,
subordinates ARRAY<STRING>,
deductions MAP<STRING,FLOAT>,
address STRUCT<street:STRING, city:STRING, state:STRING, zip:STRING>
);
文本文件数据编码
常见的文本文件的格式,有以逗号和制表符分隔的文本文件,也就是所谓的逗号分隔值(CSV)或制表符分隔值(TSV)。只要用户需要,Hive是支持这些文件格式的。然而,这两种格式的文件有一个共同的缺点,那就是:
用户需要对文本文件中那些不需要作为分隔符处理的逗号或者制表符格外小心
也因此,Hive默认使用了几个控制字符,这些字符很少出现在字段值中。Hive使用术语field来表示替换分隔符的字符。
Hive中默认的记录和字段分隔符如下表:
分隔符 | 描述 |
---|---|
\n | 对于文本来说,每行都是一条记录,因此换行符可以分割记录 |
^A(Ctrl+A) | 用于分割字段(列)。在CREATE TABLE 语句中可以使用八进制编码\001表示 |
^B | 用于分割ARRAY或者STRUCT中的元素,或用于MAP中键值对之间的分割。在CREATE TABLE语句中可以使用八进制编码\002表示 |
^C | 用于MAP中键和值之间的分割。在CREATE TABLE语句中可以使用八进制编码\003表示 |
我们看一下employees表中的记录,其中使用了^A等字符作为字段分割符:
用户可以不使用这些默认分隔符,而指定使用其他分隔符。下面这个表结构和和之前那个表是一样的,不过这里明确制定了分隔符:
CREATE TABLE employees(
name STRING,
salary FLOAT,
subordinates ARRAY<STRING>,
deductions MAP<STRING,FLOAT>,
address STRUCT<street:STRING, city:STRING, state:STRING, zip:STRING>
)
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 ...)之前
读时模式
传统的数据库是写时模式(schema on write),即数据在写入数据库时对模式进行检查。
Hive对底层存储并没有这样的控制。Hive不会在数据加载时进行验证,而是在查询时进行,也就是读时模式。
那么如果模式和文件内容不匹配将会怎么样呢?
Hive对此做的非常好,因为其可以读取这些数据。如果每行记录汇总字段个数少于对应模式中定义的字段个数的话,那么用户将会看到查询结果中有很多null值。如果某些字段是数值型,但Hive在读取时发现存在非数值型的字符串值的话,那么对于那些字段将会返回null值。除此之外的情况,Hive都极力尝试尽可能将各种错误恢复过来