目录
[📊 Hive 离线数仓分层操作规范](#📊 Hive 离线数仓分层操作规范)
[三、分层建表与 ETL 实现](#三、分层建表与 ETL 实现)
[✅ 步骤 1:ODS 层 ------ 原始日志表](#✅ 步骤 1:ODS 层 —— 原始日志表)
[1.1 创建 ODS 表(外部表)](#1.1 创建 ODS 表(外部表))
[1.2 加载数据(每日分区)](#1.2 加载数据(每日分区))
[1.3 添加分区](#1.3 添加分区)
[✅ 步骤 2:DWD 层 ------ 清洗后的明细表](#✅ 步骤 2:DWD 层 —— 清洗后的明细表)
[2.1 创建 DWD 表](#2.1 创建 DWD 表)
[2.2 ETL:从 ODS 解析并清洗](#2.2 ETL:从 ODS 解析并清洗)
[✅ 步骤 3:DWS 层 ------ 轻度汇总表](#✅ 步骤 3:DWS 层 —— 轻度汇总表)
[3.1 创建 DWS 表(按天、按事件聚合)](#3.1 创建 DWS 表(按天、按事件聚合))
[3.2 ETL:从 DWD 聚合](#3.2 ETL:从 DWD 聚合)
[✅ 步骤 4:ADS 层 ------ 应用指标表(面向报表)](#✅ 步骤 4:ADS 层 —— 应用指标表(面向报表))
[4.1 创建 ADS 表(最终展示字段)](#4.1 创建 ADS 表(最终展示字段))
[4.2 ETL:多指标整合(可来自多个 DWS 表)](#4.2 ETL:多指标整合(可来自多个 DWS 表))
[四、导出 ADS 到 MySQL](#四、导出 ADS 到 MySQL)
[方式:使用 Spark(推荐)或 Sqoop](#方式:使用 Spark(推荐)或 Sqoop)
[Spark 导出示例(PySpark)](#Spark 导出示例(PySpark))
[1. 任务调度(Airflow 示例 DAG)](#1. 任务调度(Airflow 示例 DAG))
[2. 监控项](#2. 监控项)
📊 Hive 离线数仓分层操作规范
目标 :构建清晰、可维护、高性能的离线数据仓库,支撑报表与 BI 可视化
适用场景:日志分析、用户行为、业务指标统计等批处理任务
一、各层定义与职责
表格
| 层级 | 全称 | 职责 | 特点 |
|---|---|---|---|
| ODS | Operational Data Store | 存放原始数据,不做清洗或仅做轻度清洗 | 与源系统结构一致,保留全量历史 |
| DWD | Data Warehouse Detail | 清洗、脱敏、标准化、维度退化后的明细事实表 | 统一命名、统一编码、统一单位 |
| DWS | Data Warehouse Summary | 按主题/维度聚合的轻度汇总表(如日活、订单总额) | 宽表设计,减少后续 JOIN |
| ADS | Application Data Service | 面向具体业务场景的最终指标表 | 直接对接报表、API、MySQL |
二、示例业务:用户行为日志分析
-
原始日志格式(JSON) :
sql{"user_id":"U1001","event":"click","page":"home","ts":1710489600}
三、分层建表与 ETL 实现
✅ 步骤 1:ODS 层 ------ 原始日志表
1.1 创建 ODS 表(外部表)
sql
-- 数据库
CREATE DATABASE IF NOT EXISTS ods;
USE ods;
-- 外部表,指向 HDFS 路径
CREATE EXTERNAL TABLE ods.user_log_ods (
raw_data STRING COMMENT '原始 JSON 字符串'
)
PARTITIONED BY (dt STRING)
STORED AS TEXTFILE
LOCATION '/data/ods/user_log';
1.2 加载数据(每日分区)
sql
# 模拟 HDFS 写入
hdfs dfs -put /local/logs/2026-03-15.log /data/ods/user_log/dt=2026-03-15/
1.3 添加分区
sql
ALTER TABLE ods.user_log_ods ADD PARTITION (dt='2026-03-15');
✅ 步骤 2:DWD 层 ------ 清洗后的明细表
2.1 创建 DWD 表
sql
CREATE DATABASE IF NOT EXISTS dwd;
USE dwd;
CREATE TABLE dwd.user_log_dwd (
user_id STRING COMMENT '用户ID',
event STRING COMMENT '事件类型',
page STRING COMMENT '页面',
ts BIGINT COMMENT '时间戳',
dt STRING COMMENT '日期分区'
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET
TBLPROPERTIES ("parquet.compression"="SNAPPY");
2.2 ETL:从 ODS 解析并清洗
sql
INSERT OVERWRITE TABLE dwd.user_log_dwd PARTITION (dt='2026-03-15')
SELECT
get_json_object(raw_data, '$.user_id') AS user_id,
get_json_object(raw_data, '$.event') AS event,
get_json_object(raw_data, '$.page') AS page,
CAST(get_json_object(raw_data, '$.ts') AS BIGINT) AS ts,
'2026-03-15' AS dt
FROM ods.user_log_ods
WHERE dt = '2026-03-15'
AND get_json_object(raw_data, '$.user_id') IS NOT NULL;
✅ 清洗规则:过滤空 user_id、转换时间格式、统一事件命名(如 click → CLICK)
✅ 步骤 3:DWS 层 ------ 轻度汇总表
3.1 创建 DWS 表(按天、按事件聚合)
sql
CREATE DATABASE IF NOT EXISTS dws;
USE dws;
CREATE TABLE dws.user_event_daily (
event_type STRING COMMENT '事件类型',
active_users BIGINT COMMENT '活跃用户数',
event_count BIGINT COMMENT '事件次数'
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET;
3.2 ETL:从 DWD 聚合
sql
INSERT OVERWRITE TABLE dws.user_event_daily PARTITION (dt='2026-03-15')
SELECT
event AS event_type,
COUNT(DISTINCT user_id) AS active_users,
COUNT(*) AS event_count
FROM dwd.user_log_dwd
WHERE dt = '2026-03-15'
GROUP BY event;
✅ 步骤 4:ADS 层 ------ 应用指标表(面向报表)
4.1 创建 ADS 表(最终展示字段)
sql
CREATE DATABASE IF NOT EXISTS ads;
USE ads;
CREATE TABLE ads.daily_report (
stat_date STRING COMMENT '统计日期',
total_users BIGINT COMMENT '总活跃用户',
click_count BIGINT COMMENT '点击次数',
home_uv BIGINT COMMENT '首页UV'
)
STORED AS PARQUET;
4.2 ETL:多指标整合(可来自多个 DWS 表)
sql
INSERT OVERWRITE TABLE ads.daily_report
SELECT
'2026-03-15' AS stat_date,
SUM(active_users) AS total_users,
SUM(CASE WHEN event_type = 'click' THEN event_count ELSE 0 END) AS click_count,
SUM(CASE WHEN event_type = 'click' AND page = 'home' THEN 1 ELSE 0 END) AS home_uv
FROM (
SELECT event_type, active_users, event_count
FROM dws.user_event_daily
WHERE dt = '2026-03-15'
) t;
💡 实际中可 JOIN 多个 DWS 表(如订单、支付)生成综合日报表。
四、导出 ADS 到 MySQL
方式:使用 Spark(推荐)或 Sqoop
Spark 导出示例(PySpark)
python
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("ads_to_mysql").getOrCreate()
df = spark.sql("SELECT * FROM ads.daily_report")
df.write \
.format("jdbc") \
.option("url", "jdbc:mysql://mysql-host:3306/report_db?useSSL=false") \
.option("dbtable", "daily_report") \
.option("user", "report_user") \
.option("password", "secure_password") \
.mode("overwrite") \
.save()
⚠️ 注意:确保 MySQL 表结构与 Hive ADS 表字段兼容(如 STRING → VARCHAR(255))。
五、调度与运维建议
1. 任务调度(Airflow 示例 DAG)
python
from airflow import DAG
from airflow.providers.apache.hive.operators.hive import HiveOperator
from airflow.operators.bash import BashOperator
with DAG('user_log_etl', schedule_interval='@daily') as dag:
ods_to_dwd = HiveOperator(
task_id='ods_to_dwd',
hql='INSERT OVERWRITE ... FROM ods.user_log_ods WHERE dt="{{ ds }}"'
)
dwd_to_dws = HiveOperator(task_id='dwd_to_dws', hql='...')
dws_to_ads = HiveOperator(task_id='dws_to_ads', hql='...')
export_to_mysql = BashOperator(task_id='export_to_mysql', bash_command='spark-submit ...')
ods_to_dwd >> dwd_to_dws >> dws_to_ads >> export_to_mysql
2. 监控项
- 各层数据量环比波动(±20% 告警)
- 任务执行时长(超阈值告警)
- MySQL 导出成功状态
六、附录:目录结构建议
Dart
/data/
├── ods/
│ └── user_log/dt=2026-03-15/
├── dwd/
│ └── user_log_dwd/dt=2026-03-15/
├── dws/
│ └── user_event_daily/dt=2026-03-15/
└── ads/
└── daily_report/
七、总结
| 层级 | 关键动作 | 输出 |
|---|---|---|
| ODS | 原始数据接入 | 1:1 原始日志 |
| DWD | 清洗、解析、标准化 | 高质量明细 |
| DWS | 聚合、宽表 | 主题汇总 |
| ADS | 指标对齐业务 | 报表就绪数据 |
✅ 优势:
- 解耦原始数据与业务逻辑
- 提升查询性能(避免重复 JOIN)
- 便于数据治理与血缘追踪
📌 提示 :在生产环境中,建议结合 Apache Atlas 做元数据管理,DataX / Seatunnel 做异构数据同步,Prometheus + Grafana 做任务监控。