本科毕业设计项目 · 完整数仓分层建设 + 交互式看板 + OLAP 引擎选型对比
数据集:飞猪旅游电商用户行为数据(2019-06 ~ 2021-06)https://tianchi.aliyun.com/dataset/113649
本项目基于真实的旅游电商用户行为数据,搭建了一套完整的离线数据仓库,并在 ADS 层之上引入 Apache Doris 作为 OLAP 查询引擎,对接 Streamlit 看板对外提供毫秒级响应的交互式数据服务。
项目重点解决三个问题:
- 如何按规范化的分层架构(ODS → DWD → DWM → DWS → ADS)组织数仓建设
- 如何通过 Spark + Hive 完成端到端的离线 ETL
- 为什么需要在 Hive 之上再引入 Doris —— 通过端到端 benchmark 量化对比验证
- 完整的数仓分层 —— ODS / DWD / DWM / DWS / ADS 五层均落地,每层均有 DDL 和 ETL 脚本
- 批查分离架构 —— Hive 承担离线批处理 ETL,Doris 承担 ADS 之上的实时查询服务
- 三主题看板 —— 用户画像、转化漏斗、商品运营,覆盖电商分析典型场景
- Doris vs Hive 实测对比 —— 同一查询负载下 Doris 较 Hive 平均加速 [XXX] 倍,毫秒级响应 vs 秒/分钟级响应
整体数据流向:
原始数据 (CSV)
│
▼
Spark ETL ──► Hive (HDFS)
│
├── ODS 原始落地
├── DWD 维度建模 + 行为事实拆分
├── DWM 行为宽表 + 用户-商品关系汇总
├── DWS 主题轻聚合
└── ADS 应用层指标汇总
│
▼
Apache Doris (MPP OLAP)
│
▼
Streamlit 交互式看板
ETL 由 Spark 任务承担,落地到 Hive 各分层;ADS 层结果同步双写到 Doris,由 Doris 接管所有看板交互查询。
| 层 | 职责 | 关键表 |
|---|---|---|
| ODS | 原始数据落地,结构与源数据一致,仅做基础清洗 | ods_user_profile · ods_item_profile · ods_user_item_behavior_history |
| DWD | 维度建模 + 行为事实按类型拆分(点击/收藏/加购/支付) | dwd_dim_user · dwd_dim_item · dwd_user_click_di · dwd_user_fav_di · dwd_user_cart_di · dwd_user_pay_di |
| DWM | 中间层,行为宽表 + 用户-商品关系汇总 | dwm_user_behavior_wide_di · dwm_user_item_relation_df |
| DWS | 主题轻聚合,按用户/商品维度做日粒度汇总 | dws_user_behavior_agg · dws_item_behavior_agg |
| ADS | 看板直接消费层,按业务主题预聚合 | ads_user_profile_summary · ads_funnel_conversion · ads_item_ranking |
看板基于 Streamlit + Plotly 实现,由 Doris 提供查询服务。包含三个业务主题 Tab:
总览 KPI(活跃 / 支付 / 复购用户数与复购率) + 多维分布(年龄段 / 性别 / 活跃度分层 / TOP10 城市 / 用户标签)。
整体漏斗(点击 → 收藏 → 加购 → 支付)+ 关键转化率 + 分维度(年龄/性别/城市/标签)漏斗对比。
销量 TOP10、销量时序趋势、类目 × 城市热力图、TOP15 类目/城市分布、高点击低转化商品识别。
为验证在 ADS 之上引入 OLAP 引擎的必要性,搭建相同 schema 的 Hive 表(ORC + Snappy + 二级分区),对看板代码中提取的 15 条 SQL 在两个引擎上分别执行,每条跑 6 次取热查询均值对比。
- Doris 单查询热响应耗时普遍在 10~20 ms 区间
- Hive on MR 单查询热响应耗时普遍在 1.13~3.86 s 区间
- 最大加速比 232 倍(出现在聚合分析类查询上)
- 看板"用户画像"Tab 端到端加载耗时:Doris 0.1 s vs Hive 10.9 s
差距主要来自架构层面的设计取向不同:
| 维度 | Doris (MPP OLAP) | Hive (Batch ETL) |
|---|---|---|
| 进程模型 | BE 节点常驻,无任务启动开销 | 每条 SQL 触发新 MR/Tez 作业(5~30s 启动开销) |
| 计算模型 | 向量化执行,按批处理列数据 | 默认按行处理(火山模型) |
| Shuffle | 内存 + 网络 | HDFS 磁盘落盘 |
| 设计目标 | 交互式 OLAP 查询服务 | 离线批处理 ETL |
这一对比并非否定 Hive 的价值。Hive/Spark 仍承担本系统上游 ODS → DWD → DWM → DWS → ADS 的离线批处理 ETL,Doris 仅接管 ADS 之上的查询服务,构成"批处理 + 实时查询"的分层架构。
benchmark 脚本:src/main/Doris/py/bench_doris_vs_hive.py
data_warehouse/
├── pom.xml # Maven 工程配置
├── README.md # 本文件
├── docs/ # 文档与图片资源
│ ├── architecture.png # 系统架构图
│ └── screenshots/ # 看板截图
│ ├── dashboard_user_profile.png
│ ├── dashboard_funnel.png
│ └── dashboard_item.png
└── src/main/
├── ODS/
│ ├── DDL/ # 三张原始表建表
│ └── py/ # 数据探查与拆分脚本
├── DWD/
│ ├── DDL/ # 维度表 + 4 张行为事实表
│ └── ETL/ # 对应 Spark SQL 处理逻辑
├── DWM/
│ ├── DDL/
│ └── ETL/ # 行为宽表 + 用户商品关系汇总
├── DWS/
│ ├── DDL/
│ └── ETL/ # 用户/商品主题轻聚合
├── ADS/
│ ├── DDL/ # 三张应用层汇总表
│ └── ETL/ # 业务指标计算逻辑
└── Doris/
├── DDL/ # Doris 端三张 ADS 表建表
├── sample/ # 示例数据 / 测试 SQL
└── py/
├── dashboard.py # Streamlit 看板入口
├── bench_doris_vs_hive.py # 性能对比 benchmark
├── fig_per_query.png # benchmark 输出
├── fig_per_tab.png
└── fig_speedup.png
| 组件 | 版本 |
|---|---|
| Hadoop / HDFS | 3.x |
| Hive | 3.x |
| Apache Spark | 3.x |
| Apache Doris | 2.x |
| Python | 3.12 |
| Java + Maven | JDK 8/11 + Maven 3.x |
Python 依赖:
pip install streamlit pandas plotly sqlalchemy pymysql pyhive thrift pure-sasl thrift_sasl --no-deps matplotlib- 将原始 CSV 数据上传到 HDFS
- 执行
src/main/ODS/DDL/*.sql建立 ODS 层表 - 通过
LOAD DATA或 Spark 任务导入 ODS
按 ODS → DWD → DWM → DWS → ADS 依次执行各层 ETL:
# 示例:用 spark-sql 执行某层 ETL
spark-sql -f src/main/DWD/ETL/dwd_user_click_di.sql
spark-sql -f src/main/DWS/ETL/dws_user_behavior_agg.sql
spark-sql -f src/main/ADS/ETL/ads_user_profile_summary.sql
# ... 其他表同理- 执行
src/main/Doris/DDL/*.sql在 Doris 建立 ADS 表 - 通过 Stream Load / Broker Load 把 Hive ADS 数据同步到 Doris
cd src/main/Doris/py
streamlit run dashboard.py浏览器打开 http://localhost:8501 即可查看看板。
cd src/main/Doris/py
python bench_doris_vs_hive.py脚本会分别连接 Doris 和 Hive,对相同 15 条看板 SQL 各执行 6 次,输出耗时对比表与 3 张 PNG 图。
- 数据集:飞猪旅游电商用户行为数据集
- 开源项目:Apache Spark · Apache Hive · Apache Doris · Streamlit · Plotly
本项目仅用于学习与研究目的,数据集版权归原始来源方所有。






