第7章 Hive实战
把 SQL 能力搬到 Hadoop 上:Hive 的存储格式、数据类型、HiveQL、自定义函数与 Sqoop 数据迁移。
本章学习目标
- 能说出 Hive 的定位、文件存储格式与数据类型
- 能安装并验证 Hive(含 MySQL 元数据库)
- 能用 HiveQL 完成库表操作、查询、索引与视图
- 能使用复合数据类型与编写 UDF/UDAF
- 能用 Sqoop 在 MySQL 与 Hive 之间迁移数据
本章导览
核心内容
Hive概述
Hive 是构建在 Hadoop 之上的数据仓库工具:把 HDFS 上的文件映射成表,把 HiveQL 翻译成 MapReduce/Tez 作业执行。
Hive的文件存储格式
| 格式 | 类型 | 特点 |
|---|---|---|
| TEXTFILE | 行存 | 可读性好、压缩率低,适合导入与小数据 |
| ORC | 列存 | 压缩率高、查询快,Hive 官方推荐 |
| PARQUET | 列存 | 跨平台兼容性好,适合与 Spark 共用 |
Hive支持的数据类型
| 类别 | 类型 |
|---|---|
| 基本类型 | TINYINT / SMALLINT / INT / BIGINT / FLOAT / DOUBLE / BOOLEAN / STRING / TIMESTAMP |
| 复合类型 | ARRAY、MAP、STRUCT、UNIONTYPE |
CREATE TABLE t_complex(
id INT,
hobbies ARRAY<STRING>, -- 数组
scores MAP<STRING, INT>, -- 键值对
info STRUCT<name:STRING, age:INT>
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '|'
MAP KEYS TERMINATED BY ':'
STORED AS TEXTFILE;安装与验证Hive
两条依赖:元数据库(MySQL)与 HDFS。装完用 <code class="inl">schematool -initSchema</code> 初始化元数据,再用 <code class="inl">show databases;</code> 验证。
安装和配置Hive
# 1) 解压并配置环境变量
tar -zxvf apache-hive-4.1.0-bin.tar.gz -C /export/servers/
vi ~/.bashrc
export HIVE_HOME=/export/servers/hive-4.1.0
export PATH=$HIVE_HOME/bin:$PATH
# 2) 修改 hive-site.xml:指定 MySQL 元数据库
<property><name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://hadoop1:3306/hive?createDatabaseIfNotExist=true</value></property>
<property><name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value></property>
<property><name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value></property>
# 3) 放 MySQL 驱动并初始化元数据
cp mysql-connector-java-8.0.30.jar $HIVE_HOME/lib/
schematool -initSchema -dbType mysql
# 4) 验证
hive -e "show databases;"HiveQL详解
教材按"数据库操作 → 表操作 → 数据查询 → 索引和视图"四块讲,覆盖日常开发 80% 的用法。
表操作
CREATE TABLE IF NOT EXISTS student_info(
stu_id STRING COMMENT '学号',
stu_name STRING COMMENT '姓名',
sex STRING COMMENT '性别'
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS ORC;
-- 内部表 vs 外部表
CREATE EXTERNAL TABLE ext_student(...) LOCATION '/data/student';
-- 分区表
CREATE TABLE score_part(stu_id STRING, score INT)
PARTITIONED BY (course_id STRING);
-- 常用维护
DESC FORMATTED student_info;
SHOW PARTITIONS score_part;
ALTER TABLE student_info ADD COLUMNS (class_id STRING);
TRUNCATE TABLE student_info;数据查询
-- 基础查询
SELECT stu_name, sex FROM student_info WHERE sex = '男';
-- 分组统计
SELECT course_id, count(*) AS cnt, round(avg(score), 2) AS avg_score
FROM score_info GROUP BY course_id HAVING avg(score) > 60;
-- 多表连接
SELECT s.stu_name, c.course_name, sc.score
FROM score_info sc
JOIN student_info s ON sc.stu_id = s.stu_id
JOIN course_info c ON sc.course_id = c.course_id;
-- 窗口函数:取每门课前 3 名
SELECT * FROM (
SELECT course_id, stu_id, score,
rank() OVER (PARTITION BY course_id ORDER BY score DESC) rk
FROM score_info
) t WHERE rk <= 3;用户自定义函数
内置函数不够用时自己写:UDF 一行进一行出,UDAF 多行进一行出。
编写UDF
public class MyLowerUDF extends UDF {
public Text evaluate(Text input) {
if (input == null) return null;
return new Text(input.toString().toLowerCase());
}
}-- 注册与使用
ADD JAR /user/hadoop/jars/myudf.jar;
CREATE TEMPORARY FUNCTION my_lower AS 'com.demo.MyLowerUDF';
SELECT my_lower(stu_name) FROM student_info LIMIT 5;数据迁移工具Sqoop
Sqoop 用 MapReduce 在关系型数据库与 HDFS/Hive 之间批量搬运数据,是"业务库 → 数仓"的标准通道。
MySQL数据导入Hive
sqoop import \
--connect jdbc:mysql://hadoop1:3306/nev --username root --password 123456 \
--table web_chat_ems --hive-import --hive-database ods --hive-table web_chat_ems \
--fields-terminated-by '\t' -m 1-- 反向:Hive 导出到 MySQL(目标表需先建好)
sqoop export \
--connect jdbc:mysql://hadoop1:3306/nev --username root --password 123456 \
--table visit_dws \
--export-dir /user/hive/warehouse/dws.db/visit_dws \
--input-fields-terminated-by '\t'
-- 注意:导出前请确认 MySQL 端已建好同结构的接收表本章小结
本章是教材里与数据仓库直接相关的一章:先讲 Hive 的定位、存储格式与数据类型,再完成安装与元数据初始化,然后用库表操作、查询、索引视图覆盖 HiveQL 主干,接着讲复合数据类型与 UDF/UDAF,最后用 Sqoop 打通 MySQL 与 Hive 的导入导出。
思考与练习 先自己做,再点开答案
Hive 中内部表与外部表的区别?
查看参考答案
内部表由 Hive 管理数据,DROP TABLE 时元数据与数据一起删除;外部表只删元数据,HDFS 上的数据保留。接别人的数据一律用外部表。
为什么 Hive 查询比 MySQL 慢,却更适合大数据?
查看参考答案
Hive 把 SQL 翻译成分布式作业(MapReduce/Tez),启动开销大、延迟高(分钟级),但可以横向扩展到成百上千节点处理 TB/PB 级数据;MySQL 单机毫秒级响应,但数据量到 GB/TB 级别就撑不住。
UDF 与 UDAF 的区别?
查看参考答案
UDF(User Defined Function)一行输入一行输出,如大小写转换;UDAF(User Defined Aggregation Function)多行输入一行输出,如自定义求和/求均值。
Sqoop 导入时为什么常加 -m 1?
查看参考答案
-m 1 表示只用 1 个 Map 任务,避免导出多个文件、也避免 MySQL 端压力过大;数据量大时可按主键切分多个 Map 并行导入。