跟着黑马学Hive - 第一周

200 阅读11分钟

🐎本文来源:整理自黑马程序员B站课程

🔗课程链接:www.bilibili.com/video/BV1L5…

✒️本文作者:Anthony_4926

1. 常见的 Hive 开发方式

推荐使用

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, ...)];

为了看着更方便,贴一个截图

image.png

  • 蓝色字体是建表语法的关键字,用于指定某些功能。
  • []中括号的语法表示可选。
  • |表示使用的时候,左右语法二选一。
  • 建表语句中的语法顺序要和语法树中顺序保持一致。

3. Hive 数据类型

3.1. 整体概述

  • Hive 数据类型指的是表中列的字段类型;

  • 整体分为两类:原生数据类型(primitive data type)和复杂数据类型(complex data type)。

    • 原生数据类型包括:数值类型时间日期类型字符串类型杂项数据类型
    • 复杂数据类型包括:array数组map映射struct结构union联合体

image.png

3.2. 原生数据类型

image.png

3.3. 复杂数据类型

image.png

主要关注 array 和 map 即可,struct 和 union 目前 Hive 支持的还不是很完善。

3.4. 注意事项

  • Hive SQL 中,数据类型英文字母大小写不敏感;
  • 除 SQL 数据类型外,还支持 Java 数据类型,比如字符串 string;
  • 复杂数据类型的使用通常需要和分隔符指定语法配合使用;(后边会有例子)
  • 如果定义的数据类型和文件不一致,Hive 会尝试隐式转换,但是不保证成功。

3.5. 隐式类型转换

  • 与标准 SQL 类似,HQL 支持隐式和显式类型转换。
  • 原生类型从窄类型到宽类型的转换称为隐式转换,反之,则不允许。
  • 下表描述了类型之间允许的隐式转换:
voidbooleantinyintsmallintintbigintfloatdouble
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 读写文件流程

image.png

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 类进行序列化;
  • 如何指定分隔符。

image.png

其中 ROW FORMAT 是语法关键字,DELIMITED 和 SERDE 二选其一。

  • 如果使用 DELIMITED 表示使用默认的 LazySimpleSerDe 类来处理数据。
  • 如果数据文件格式比较特殊可以使用 ROW FORMAT SERDE serde_name 指定其他的 Serde 类来处理数据,甚至支持用户自定义 SerDe 类。

image.png

4.4. LazySimpleSerDe 分隔符指定

LazySimpleSerDe 是 Hive 默认的序列化类,包含 4 种子语法,分别用于指定字段之间、集合元素之间、map 映射 kv 之间、换行的分隔符号。后边也都有例子

在建表的时候可以根据数据的特点灵活搭配使用。

image.png

4.5. 默认分隔符

Hive 建表时如果没有 row format 语法指定分隔符,则采用默认分隔符;

默认的分割符是'\001',是一种特殊的字符,使用的是 ASCII 编码的值,键盘是打不出来的。

image.png

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 可以直接存取。

image.png

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 语法进行指定。

image.png

 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 之间分隔符。

image.png

 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 中建表映射成功该文件。

image.png

 create table t_team _ace_player_location(
     id int
     , team_name string
     , ace_player_name string
 )
 location '/data'; --使用location关键字指定本张表数据在hdfs上的存储路径

7. 内部表、外部表

image.png

7.1. 什么是内部表

  • 内部表(Internal table)也称为被 Hive 拥有和管理的托管表(Managed table)。
  • 默认情况下创建的表就是内部表,Hive 拥有该表的结构和文件。换句话说,Hive 完全管理表(元数据和数据)的生命周期,类似于 RDBMS 中的表。
  • 当您删除内部表时,它会删除数据以及表的元数据。

可以使用 DESCRIBE FORMATTED tablename,来获取表的元数据描述信息,从中可以看出表的类型。

image.png

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 再探究

思考

  1. 在创建外部表的时候,可以使用 location 指定存储位置路径,如果不指定会如何?
  2. 创建内部表的时候,是否可以使用 location 指定?
  3. 是否意味着 Hive 表的数据在 HDFS 上的位置不是一定要在/user/hive/warehouse 下?

Location 与内外部表并无因果关系,彼此独立。因此,上述问题的答案也就显而易见了

  1. 不指定 location 就使用默认位置 /user/hive/warehouse
  2. 可以,同样是指定在哪里,Hive 就会到哪里去映射文件
  3. 是的,使用 location 指定到哪里,就是哪里。当然也可以通过修改hive.metastore.warehouse.dir重新定义默认路径。