🐎本文来源:整理自黑马程序员B站课程
🔗课程链接:www.bilibili.com/video/BV1L5…
✒️本文作者:Anthony_4926
1. 常见的 Hive 开发方式
推荐使用
- dbeaver:免费的
- jetbrains 全家桶任意一款:收费的、学生认证免费
2. 建表语法树剖析
这里语法树提供一个概览,后边会更详细的说每一个规则
CREATE [TEMPORARY][EXTERNAL] TABLE [IF NOT EXISTS][db_name.] table_name
[(col_name data [COMMENT col_comment]),...]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...) INTO num_buckets BUCKETS]]
[ROW FORMAT DELIMITED|SERDE serde_name WITH SERDEPROPERTIES (property_name=property_value, ...)]
[STORED AS file_format]
[LOCATION hfds_path]
[TBLPROPERTIES (property_name=property_value, ...)];
为了看着更方便,贴一个截图
- 蓝色字体是建表语法的关键字,用于指定某些功能。
[]中括号的语法表示可选。|表示使用的时候,左右语法二选一。- 建表语句中的语法顺序要和语法树中顺序保持一致。
3. Hive 数据类型
3.1. 整体概述
-
Hive 数据类型指的是表中列的字段类型;
-
整体分为两类:原生数据类型(primitive data type)和复杂数据类型(complex data type)。
- 原生数据类型包括:
数值类型、时间日期类型、字符串类型、杂项数据类型; - 复杂数据类型包括:
array数组、map映射、struct结构、union联合体。
- 原生数据类型包括:
3.2. 原生数据类型
3.3. 复杂数据类型
主要关注 array 和 map 即可,struct 和 union 目前 Hive 支持的还不是很完善。
3.4. 注意事项
- Hive SQL 中,数据类型英文字母大小写不敏感;
- 除 SQL 数据类型外,还支持 Java 数据类型,比如字符串 string;
- 复杂数据类型的使用通常需要和分隔符指定语法配合使用;(后边会有例子)
- 如果定义的数据类型和文件不一致,Hive 会尝试隐式转换,但是不保证成功。
3.5. 隐式类型转换
- 与标准 SQL 类似,HQL 支持隐式和显式类型转换。
- 原生类型从窄类型到宽类型的转换称为隐式转换,反之,则不允许。
- 下表描述了类型之间允许的隐式转换:
| void | boolean | tinyint | smallint | int | bigint | float | double | |
|---|---|---|---|---|---|---|---|---|
| void to | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| boolean to | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| tinyint to | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| smallint to | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
| int to | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
| bigint to | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
| float to | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
3.6. 显式类型转换
显式类型转换使用 CAST 函数。
例如,CAST ('100' as INT) 会将 100 字符串转换为 100 整数值。
如果强制转换失败,例如CAST ('anthony' as INT) , 该函数返回 NULL。
4. Hive 读写文件机制
Hive 是建立在 Hadoop 之上的数据仓库基础架构,它的数据存储依赖于 Hadoop 的分布式文件系统,通常是 HDFS。
hdfs 中的文件可以是.txt,只要是字段间分隔符统一,Hive 就能正常读取。先简单举一个例子,后边会细说。
如下student.txt 文件,字段间分隔符是\t。
1 Alice 20
2 Bob 21
3 Charlie 22
4.1. SerDe 是什么
SerDe 是 Serializer、Deserializer 的简称,目的是用于序列化和反序列化。
序列化是对象转化为字节码的过程;而反序列化是字节码转换为对象的过程。
Hive 使用 SerDe(包括 FileFormat)读取和写入表行对象。需要注意的是,key部分在读取时会被忽略,而在写入时key始终是常数。基本上行对象存储在value中。
4.2. Hive 读写文件流程
Hive 读取文件机制:首先调用 InputFormat(默认 TextInputFormat),返回一条一条 kv 键值对记录(默认是一行对应一条键值对)。然后调用 SerDe(默认 LazySimpleSerDe)的 Deserializer,将一条记录中的 value 根据分隔符切分为各个字段。
TextInputFormat是 Hadoop 中的一个处理输入格式的工具类
Hive 写文件机制:将 Row 写入文件时,首先调用 SerDe(默认 LazySimpleSerDe)的 Serializer 将对象转换成字节序 列,然后调用 OutputFormat 将数据写入 HDFS 文件中。
4.3. row format 语法
ROW FORMAT 这一行所代表的是跟读写文件、序列化 SerDe 相关的语法,功能有二:
- 使用哪个 SerDe 类进行序列化;
- 如何指定分隔符。
其中 ROW FORMAT 是语法关键字,DELIMITED 和 SERDE 二选其一。
- 如果使用 DELIMITED 表示使用默认的 LazySimpleSerDe 类来处理数据。
- 如果数据文件格式比较特殊可以使用 ROW FORMAT SERDE serde_name 指定其他的 Serde 类来处理数据,甚至支持用户自定义 SerDe 类。
4.4. LazySimpleSerDe 分隔符指定
LazySimpleSerDe 是 Hive 默认的序列化类,包含 4 种子语法,分别用于指定字段之间、集合元素之间、map 映射 kv 之间、换行的分隔符号。后边也都有例子
在建表的时候可以根据数据的特点灵活搭配使用。
4.5. 默认分隔符
Hive 建表时如果没有 row format 语法指定分隔符,则采用默认分隔符;
默认的分割符是'\001',是一种特殊的字符,使用的是 ASCII 编码的值,键盘是打不出来的。
5. Hive 数据存储路径
5.1. 默认存储路径
- 再次强调,Hive 本身并不存储数据,它的数据放在 HDFS 上。
- Hive 表默认存储路径是由
${HIVE_HOME}/conf/hive-site.xml配置文件的hive.metastore.warehouse.dir属性指定,默认值是:/user/hive/warehouse。 - 在该路径下,文件将根据所属的库、表,有规律的存储在对应的文件夹下。
如果修改了hive.metastore.warehouse.dir那么 Hive 下所有的文件存储路径都将被修改。现在想仅仅某个表的创建路径指定,那就可以使用 locatio 关键字。
5.2. Location 修改数据存储路径
在 Hive 建表的时候,可以通过 location 语法来更改数据在 HDFS 上的存储路径,使得建表加载数据更加灵活方便。语法:LOCATION '<hdfs_location>'。
对于已经生成好的数据文件,使用 location 指定路径就能在不改变文件位置的情况下,将 Hive 与文件进行关联映射,Hive 可以直接存取。
6. 建表语法练习
6.1. 基本数据类型使用
文件 archer.txt 中记录了手游《王者荣耀》射手的相关信息,包括生命、物防、物攻等属性信息,其中字段之间分隔符为制表符\t,要求在 Hive 中建表映射成功该文件。
- 字段含义:id、name(英雄名称)、hp_max(最大生命)、mp_max(最大法力)、attack_max(最高物攻)、
defense_max(最大物防)、attack_range(攻击范围)、role_main(主要定位)、role_assist(次要定位)。
1 后羿 5986 1784 396 336 remotely archer
2 马可波罗 5584 200 362 344 remotely archer
3 鲁班七号 5989 1756 400 323 remotely archer
4 李元芳 5725 1770 396 340 remotely archer
5 孙尚香 6014 1756 411 346 remotely archer
6 黄忠 5898 1784 403 319 remotely archer
7 狄仁杰 5710 1770 376 338 remotely archer
8 虞姬 5669 1770 407 329 remotely archer
9 成吉思汗 5799 1742 394 329 remotely archer
10 百里守约 5611 1784 410 329 remotely archer assassin
- 分析一下:字段都是基本类型,字段的顺序需要注意一下。
- 字段之间的分隔符是制表符,需要使用 row format 语法进行指定。
create table t_archer(
id int comment 'id'
, name string comment '英雄名称'
, hp_max int comment '最大生命'
, mp_max int comment '最大法力'
, attack_max int comment '最高物攻'
, defense_max int comment '最大物防'
, attack_range string comment '攻击范围'
, role_main string comment '主要定位'
, role_assit string comment '次要定位'
)comment '王者荣耀射手信息'
row format delimited
fields terminated by '\t'
;
想一想:Hive 这种直接映射文件的能力是不是比 mysql 一条一条 insert 插入数据方便多了?
6.2. 复杂数据类型使用
文件 hot_hero_skin_price.txt 中记录了手游《王者荣耀》热门英雄的相关皮肤价格信息,要求在 Hive 中建表映射成功该文件。
- 字段:id、name(英雄名称)、win_rate(胜率)、skin_price(皮肤及价格);
2,鲁班七号,54,木偶奇遇记:288—福禄兄弟:288—黑桃队长:60—电玩小子:2288—星空梦想:0
3,后裔,53,精灵王:288—阿尔法小队:588—辉光之辰:888—黄金射手座:1688—如梦令:1314
4,铠,52,龙域领主:288—曙光守护者:1776
5,韩信,52,飞衡:1788—逐梦之影:888—白龙吟:1188—教廷特使:0—街头霸王:888
- 分析一下:前 3 个字段原生数据类型、最后一个字段复杂类型 map。
- 需要指定字段之间分隔符、集合元素之间分隔符、map kv 之间分隔符。
create table t_hot_hero_skin_price(
id int comment 'id'
, name string comment '英雄名称'
, win_rate int comment '胜率'
, skin_price map<string, int> comment '皮肤及价格'
) comment '热门英雄的相关皮肤价格信息'
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':';
6.3. 默认分隔符使用
文件 team_ace_player.txt 中记录了手游《王者荣耀》主要战队内最受欢迎的王牌选手信息,字段之间使用的是\001作为分隔符,要求在 Hive 中建表映射成功该文件。
- 字段:id、team_name(战队名称)、ace_player_name(王牌选手名字)
- 分析一下:数据都是原生数据类型,且字段之间分隔符是\001,因此在建表的时候可以省去 row format 语句,因为 hive 默认的分隔符就是\001。
create table t_team_ace_player (
id int
, team_name string
, ace_player_name string
)
想一想:字段以\001分隔建表时很方便,那么采集、清洗数据时对数据格式追求有什么启发?你青睐于什么分隔符?
6.4. 指定数据存储路径
文件 team ace_player.txt 中记录了手游《王者荣耀》主要战队内最受欢迎的王牌选手信息,字段之间使用的是\001 作为分隔符。
要求把文件上传到 HDFS 任意路径下,不能移动复制,并在 Hive 中建表映射成功该文件。
create table t_team _ace_player_location(
id int
, team_name string
, ace_player_name string
)
location '/data'; --使用location关键字指定本张表数据在hdfs上的存储路径
7. 内部表、外部表
7.1. 什么是内部表
- 内部表(Internal table)也称为被 Hive 拥有和管理的托管表(Managed table)。
- 默认情况下创建的表就是内部表,Hive 拥有该表的结构和文件。换句话说,Hive 完全管理表(元数据和数据)的生命周期,类似于 RDBMS 中的表。
- 当您删除内部表时,它会删除数据以及表的元数据。
可以使用 DESCRIBE FORMATTED tablename,来获取表的元数据描述信息,从中可以看出表的类型。
7.2. 什么是外部表
- 外部表(External table)中的数据不是 Hive 拥有或管理的,只管理表元数据的生命周期。
- 要创建一个外部表,需要使用 EXTERNAL 语法关键字。
- 删除外部表只会删除元数据,而不会删除实际数据。数据文件始终会在那里。
- 实际场景中,外部表搭配 location 语法指定数据的路径,可以让数据更安全。
create external table student_ext(
num int
, name string
, sex string
, age int
, dept string
)
row format delimited
fileds delimited by ','
location '/stu'
;
7.3. 内、外部表差异
- 无论内部表还是外部表,Hive 都在 Hive Metastore 中管理表定义、字段类型等元数据信息。
- 删除内部表时,除了会从 Metastgre 中删除表元数据,还会从 HDFS 中删除其所有数据文件。
- 删除外部表时,只会从 Metastore 中删除表的元数据,并保持 HDFS 位置中的实际数据不变。
| 内部表、托管表 | 外部表 | |
|---|---|---|
| 创建方式 | 默认情况下 | 使用 EXTERNAL 语法关键字 |
| Hive 管理范围 | 元数据、表数据 | 元数据 |
| 删除表结果 | 删除元数据,删除 HDFS 上文件数据 | 只会删除元数据 |
| 操作 | 支持 ARCHIVE,UNARCHIVE,TRUNCATE, MERGE,CONCATENATE | 不支持 |
| 事务 | 支持 ACID / 事务性 | 不支持 |
| 缓存 | 支持结果缓存 | 不支持 |
7.4. 如何选择内、外部表
- 当需要通过 Hive 完全管理控制表的整个生命周期时,请使用内的部表。
- 当数据来之不易,防止误删,请使用外部表,因为即使删除表,文件也会被保留。
7.5. 内部表、外部表之 Location 再探究
思考
- 在创建外部表的时候,可以使用 location 指定存储位置路径,如果不指定会如何?
- 创建内部表的时候,是否可以使用 location 指定?
- 是否意味着 Hive 表的数据在 HDFS 上的位置不是一定要在/user/hive/warehouse 下?
Location 与内外部表并无因果关系,彼此独立。因此,上述问题的答案也就显而易见了
- 不指定 location 就使用默认位置
/user/hive/warehouse - 可以,同样是指定在哪里,Hive 就会到哪里去映射文件
- 是的,使用 location 指定到哪里,就是哪里。当然也可以通过修改
hive.metastore.warehouse.dir重新定义默认路径。