一、完整可运行 Hive 执行脚本
文件名规范:【学号_姓名】Hive执行脚本.sql
sql
-- ============================================================
-- 【期末考查B卷】广电用户账单营收与异常值处理 Hive 完整执行脚本
-- 对应考核模块:建库建表 → 脏数据清洗 → 财务指标统计 → 性能调优 → 本地导出
-- 数据源:Linux本地 /opt/data/mmconsume_billevents.csv
-- 字段分隔符:分号 ; (与真实CSV格式完全匹配)
-- 运行环境:Hive 3.1.2 + Hadoop 3.1.4 集群
-- ============================================================
-- ========== 会话级通用配置(仅当前终端生效,不影响全局) ==========
-- 开启查询结果列名显示,方便对应字段含义
SET hive.cli.print.header = true;
-- 关闭表名前缀,结果仅显示字段名,更简洁直观
SET hive.resultset.use.unique.column.names = false;
-- 命令行提示符显示当前数据库,避免误操作其他库
SET hive.cli.print.current.db = true;
-- ===================== 任务一:数据库与表结构构建(对应题目15分) =====================
-- 1.1 创建数据库 ZJSM_B,IF NOT EXISTS 避免重复创建报错
CREATE DATABASE IF NOT EXISTS ZJSM_B;
-- 切换到目标数据库,后续所有操作默认在该库下执行
USE ZJSM_B;
-- 1.2 创建原始账单内部表
-- 设计原则:字段顺序与CSV文件严格一一对应,彻底解决字段错位、数据全为NULL的问题
-- 内部表特性:表数据与元数据绑定,删除表时同步删除HDFS数据,适合中间计算表
CREATE TABLE IF NOT EXISTS bill_events_raw (
terminal_no STRING COMMENT '终端设备唯一编号',
phone_no STRING COMMENT '用户唯一编号',
fee_code STRING COMMENT '费用项目编码',
year_month STRING COMMENT '账单账期',
owner_name STRING COMMENT '用户等级名称',
owner_code STRING COMMENT '用户等级编码',
sm_name STRING COMMENT '业务品牌名称',
should_pay STRING COMMENT '应付金额(字符串存储,避免类型转换失败)',
favour_fee STRING COMMENT '优惠金额'
)
-- 指定字段分隔符为分号,与CSV文件格式完全一致
ROW FORMAT DELIMITED FIELDS TERMINATED BY ';'
-- 指定存储格式为纯文本文件
STORED AS TEXTFILE
-- 跳过CSV第一行表头,避免表头被当成业务数据加载
TBLPROPERTIES ("skip.header.line.count"="1");
-- 1.3 加载Linux本地CSV数据到原始表
-- LOCAL 关键字:表示从Linux服务器本地文件系统读取,而非HDFS分布式文件系统
-- OVERWRITE 关键字:覆盖表中原有数据,避免重复加载导致数据冗余
LOAD DATA LOCAL INPATH '/opt/data/mmconsume_billevents.csv'
OVERWRITE INTO TABLE bill_events_raw;
-- ✅ 验证点1:查看前5条原始数据,确认字段映射正确
-- 预期结果:sm_name为品牌名、should_pay为数字、owner_code为等级编码
SELECT * FROM bill_events_raw LIMIT 5;
-- ===================== 任务二:脏数据清洗 ETL(对应题目25分) =====================
-- 清理上一次生成的清洗结果表
DROP TABLE IF EXISTS bill_events_clean;
-- 清洗逻辑(严格匹配题目要求):
-- 规则1:剔除应付金额小于0的无效账单
-- 规则2:剔除测试线路用户(owner_code为2、9、10)
-- 规则3:仅保留广电核心品牌:数字电视、互动电视、珠江宽频
-- 兼容处理:真实数据中owner_code存在NULL值,不属于测试账号,予以保留
CREATE TABLE IF NOT EXISTS bill_events_clean AS
SELECT
phone_no,
sm_name,
owner_code,
-- 将字符串格式的应付金额转为双精度数值,用于后续财务计算
CAST(should_pay AS DOUBLE) AS should_pay
FROM bill_events_raw
WHERE
-- 过滤条件1:剔除负金额和空值异常账单
CAST(should_pay AS DOUBLE) >= 0
-- 过滤条件2:剔除内部测试账号,兼容带前导零的格式;NULL值正常用户予以保留
AND (owner_code NOT IN ('2', '9', '10', '02', '09', '10') OR owner_code IS NULL)
-- 过滤条件3:仅保留广电三大核心业务品牌
AND sm_name IN ('数字电视', '互动电视', '珠江宽频');
-- ✅ 验证点2:查看清洗后的数据量和样本数据
-- 预期结果:数据量小于原始表,无负金额、无测试账号、无违规品牌
SELECT COUNT(*) AS clean_count FROM bill_events_clean;
SELECT * FROM bill_events_clean LIMIT 10;
-- ===================== 任务三:核心财务指标统计(对应题目25分) =====================
-- ========== SQL执行性能调优参数 ==========
-- 优化1:开启Map端预聚合,Map阶段提前完成分组求和,大幅减少Shuffle数据量
SET hive.map.aggr = true;
-- 优化2:开启MapReduce中间数据压缩,降低网络IO开销,提升Shuffle效率
SET hive.exec.compress.intermediate = true;
SET mapreduce.map.output.compress = true;
-- 优化3:开启数据倾斜优化,自动拆分热点品牌的Reduce任务,解决长尾问题
SET hive.groupby.skewindata = true;
-- 优化4:开启CBO代价优化器,自动选择最优执行计划
SET hive.cbo.enable = true;
-- 核心统计SQL:统计各大品牌的总营收与独立缴费用户规模
-- 输出字段严格对应题目要求:sm_name、total_revenue、user_count
SELECT
sm_name,
-- 总营收求和,保留两位小数
ROUND(SUM(should_pay), 2) AS total_revenue,
-- 独立缴费用户数:对用户编号去重后计数
COUNT(DISTINCT phone_no) AS user_count
FROM bill_events_clean
-- 按品牌名称分组聚合
GROUP BY sm_name
-- 按总应收金额降序排列
ORDER BY total_revenue DESC;
-- ===================== 任务四:性能调优实战(对应题目15分) =====================
-- 4.1 开启Fetch抓取优化
-- 作用:简单的SELECT + LIMIT查询直接读取存储文件,不触发MapReduce任务,秒级返回结果
SET hive.fetch.task.conversion = more;
-- 4.2 开启Hive并行执行
-- 作用:SQL中多个无依赖的阶段可并行运行,缩短整体执行时间
SET hive.exec.parallel = true;
-- 设置并行执行的最大线程数,匹配集群CPU核心数
SET hive.exec.parallel.thread.number = 4;
-- ✅ 验证点3:执行简单查询,验证不再触发MapReduce任务
-- SELECT * FROM bill_events_clean LIMIT 10;
-- ===================== 任务五:数据导出与下发(对应题目20分) =====================
-- 需求:将品牌营收统计结果导出至Linux本地服务器指定目录,字段以逗号分隔
-- LOCAL 关键字:导出到Linux本地文件系统,而非HDFS
-- INSERT OVERWRITE:覆盖目标目录原有内容,保证结果唯一性
INSERT OVERWRITE LOCAL DIRECTORY '/opt/export/brand_revenue'
-- 指定导出文件的字段分隔符为逗号 ,,严格匹配题目要求
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
SELECT
sm_name,
ROUND(SUM(should_pay), 2) AS total_revenue,
COUNT(DISTINCT phone_no) AS user_count
FROM bill_events_clean
GROUP BY sm_name
ORDER BY total_revenue DESC;
-- ✅ 验证点4:Linux终端执行命令,查看本地导出结果
-- ls -l /opt/export/brand_revenue
-- cat /opt/export/brand_revenue/*
-- ========== 拓展:导出至HDFS目录(供下游大数据任务使用) ==========
/*
INSERT OVERWRITE DIRECTORY '/user/hive/export/brand_revenue_hdfs'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE
SELECT
sm_name,
ROUND(SUM(should_pay), 2) AS total_revenue,
COUNT(DISTINCT phone_no) AS user_count
FROM bill_events_clean
GROUP BY sm_name
ORDER BY total_revenue DESC;
*/
-- ✅ 验证HDFS导出结果
-- hdfs dfs -ls /user/hive/export/brand_revenue_hdfs
-- hdfs dfs -cat /user/hive/export/brand_revenue_hdfs/*二、上机实操报告模板
文件名规范:【学号_姓名】上机实操报告.docx
一、实验环境说明
- 集群环境:Hadoop 3.1.4 + Hive 3.1.2
- 元数据库:MySQL
- 操作方式:Hive CLI 命令行终端
- 数据源:HDFS 路径
/origin_data/mmconsume_billevents.csv
二、关键任务运行截图(按任务顺序粘贴)
任务 1:数据库与表结构构建
截图要求:
- 完整 Hive 终端窗口,显示
hive (ZJSM_B)提示符 - 包含建库、建表、LOAD 数据执行成功的输出
- 附带
SELECT * FROM bill_events_raw LIMIT 5;的查询结果,验证字段与分隔符正确
结果说明:
成功创建数据库 ZJSM_B 与内部表 bill_events_raw,完成 HDFS 数据加载,字段按分号正确解析,数据完整导入。
任务 2:脏数据清洗
截图要求:
- 显示
hive (ZJSM_B)提示符 - 包含 CTAS 建表执行成功的输出
- 附带
SELECT COUNT(*) FROM bill_events_clean;的统计结果
结果说明:
按照财务规则完成三轮数据过滤:剔除负金额账单、删除测试账号、保留核心品牌,清洗后数据符合业务对账标准,有效数据量为 XXX 条。
任务 3:核心财务指标统计
截图要求:
- 显示
hive (ZJSM_B)提示符 - 完整展示查询结果,包含
sm_name、total_revenue、user_count三列 - 确认金额保留两位小数,结果按总营收降序排列
结果说明:
统计得出三大核心品牌的总营收与缴费用户规模,其中 XXX 品牌营收最高,符合业务实际分布。
任务 4:性能调优实战
截图要求:
- 显示两条 SET 参数执行后的终端界面
- 附带调优后执行
SELECT * FROM bill_events_clean LIMIT 10;的结果,验证无 MapReduce 任务启动
结果说明:
开启 Fetch 抓取优化后,简单查询不再触发 MapReduce,响应速度大幅提升;开启并行执行可提升多阶段 SQL 的整体执行效率。
任务 5:数据导出与下发
截图要求:
- 第一张:Hive 终端中 INSERT 导出语句执行成功的输出
- 第二张:Linux 命令行执行
cat /opt/export/brand_revenue/*的结果,验证字段以逗号分隔
结果说明:
品牌营收统计结果已成功导出至 Linux 本地指定目录,文件字段以逗号分隔,可直接提供给财务部门对账使用。
三、实验总结
- 本次实验完整完成了广电账单数据从入库、清洗、财务统计到本地导出的全流程操作。
- 掌握了 Hive 内部表创建、HDFS 数据加载、CTAS 清洗、聚合统计、会话级参数调优、本地文件导出等核心操作。
- 关键注意事项:
- 区分 HDFS 路径加载 和 本地路径加载:HDFS 数据源不加
LOCAL,导出到本地需加LOCAL。 - 财务统计中用户数需去重,使用
COUNT(DISTINCT),避免同一用户多笔账单重复计数。 - 性能调优参数为会话级,仅对当前 Hive 连接生效,退出终端后失效。
INSERT OVERWRITE会覆盖目标目录原有数据,执行前需确认目录内容。
- 区分 HDFS 路径加载 和 本地路径加载:HDFS 数据源不加
三、答题避坑说明(得分关键点)
- 表类型区分:题目要求内部表,不要加 EXTERNAL 关键字,加错会扣分。
- LOAD 路径区分:数据源在 HDFS 上,
LOAD DATA INPATH不加LOCAL;如果是 Linux 本地文件才加LOCAL。 - 导出路径区分:导出到 Linux 本地服务器,必须加
LOCAL,即INSERT OVERWRITE LOCAL DIRECTORY,否则会导出到 HDFS。 - 字段类型匹配:
should_pay要求双精度浮点型,建表写DOUBLE,不要写成 STRING。 - 分隔符对应:建表分隔符是分号
;,导出分隔符是逗号,,两者不要写反。 - 调优参数:两个参数均为会话级 SET 命令,不需要写进建表语句,单独执行即可。
- 用户数去重:独立缴费用户数必须用
COUNT(DISTINCT phone_no),直接COUNT(*)会统计账单数而非用户数,属于逻辑错误。