Python大数据实战(十):海量数据洞察——基于Hive的电商用户购买行为全维度分析
文章目录
- Python大数据实战(十):海量数据洞察——基于Hive的电商用户购买行为全维度分析
- 前言
- 一、项目全景概览
-
- 1.1 项目目标
- 1.2 技术路线架构图
- 1.3 前置知识要求
- 二、数据建模与导入
-
- 2.1 数据集说明
- 2.2 建表语句
-
- 用户信息表
- 用户行为日志表
- 2.3 启动集群并导入数据
- 三、基础统计分析
-
- 3.1 查询用户总数
- 3.2 查询购买记录总数
- 3.3 查询卖家总数
- 四、热门商品与品牌分析
-
- 4.1 热卖商品 Top10
-
- ⚠️ 错误案例一:ORDER BY 导致单 Reduce 瓶颈
- 4.2 热卖品牌 Top10
- 4.3 购买力最强用户 Top50
- 五、时间维度消费趋势分析
-
- 5.1 不同时间戳的消费分布
- 5.2 时间戳转换:按天分析趋势
- 5.3 指定时间段消费趋势
- 六、回购率与用户画像分析
-
- 6.1 回购率排名 Top10 品牌
- 6.2 性别维度消费行为分析
-
- ⚠️ 错误案例二:LEFT JOIN 内存溢出
- 6.3 年龄维度消费行为分析
- 七、窗口函数高级分析:每品牌销量 Top3 商品
-
- 7.1 分步拆解
-
- 步骤一:统计每个品牌下每个商品的销量
- 步骤二:按品牌分组聚类
- 步骤三:使用 ROW_NUMBER() 窗口函数排名
- 7.2 窗口函数原理图解
- 八、性能优化总结
-
- 8.1 SQL 优化对照表
- 8.2 各查询性能对比
- 九、总结与展望
-
- 9.1 本文核心收获
- 9.2 扩展方向
- 9.3 下一篇预告
- 参考链接
前言
“为什么同样一款商品,有人反复购买,有人只看不买?”
电商平台每天产生数以千万计的用户行为数据——浏览、点击、加购、下单。这些数据背后隐藏着用户的消费偏好、品牌的号召力、以及时间维度上的消费趋势。但面对5492万条购买记录和42万用户信息,传统的Excel早已力不从心。
本文将带你使用 Apache Hive 在 Hadoop 集群上完成电商用户购买行为的全维度分析:从建表导入、热点商品挖掘、品牌销量排行,到用户画像(性别/年龄)分析,再到窗口函数实现"每个品牌销量Top3商品"的高级查询。全文超过 6000 字,涵盖完整SQL脚本、性能优化技巧和踩坑记录。
一、项目全景概览
1.1 项目目标
| 数据建模 | 用户表 + 行为日志表 DDL 设计 | Hive SQL |
| 数据导入 | LOAD DATA 本地文件入 Hive | HDFS + Hive |
| 基础统计 | 用户数/订单数/卖家数 | COUNT + GROUP BY |
| 热门分析 | 热卖商品Top10、热卖品牌Top10 | DISTRIBUTE BY + SORT BY |
| 用户画像 | 性别/年龄维度消费行为分析 | LEFT JOIN + GROUP BY |
| 趋势分析 | 时间维度消费趋势 | 时间戳转换 + CLUSTER BY |
| 回购分析 | 用户-品牌回购率排行 | 多字段 GROUP BY |
| 窗口分析 | 每个品牌销量Top3商品 | ROW_NUMBER() OVER(PARTITION BY) |
| 性能调优 | YARN 内存配置、SQL 优化 | MapReduce 调优 |
1.2 技术路线架构图
#mermaid-svg-JntSAx2HBOrWO1Ih{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JntSAx2HBOrWO1Ih .error-icon{fill:#552222;}#mermaid-svg-JntSAx2HBOrWO1Ih .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JntSAx2HBOrWO1Ih .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JntSAx2HBOrWO1Ih .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JntSAx2HBOrWO1Ih .marker.cross{stroke:#333333;}#mermaid-svg-JntSAx2HBOrWO1Ih svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JntSAx2HBOrWO1Ih p{margin:0;}#mermaid-svg-JntSAx2HBOrWO1Ih .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih .cluster-label text{fill:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih .cluster-label span{color:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih .cluster-label span p{background-color:transparent;}#mermaid-svg-JntSAx2HBOrWO1Ih .label text,#mermaid-svg-JntSAx2HBOrWO1Ih span{fill:#333;color:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih .node rect,#mermaid-svg-JntSAx2HBOrWO1Ih .node circle,#mermaid-svg-JntSAx2HBOrWO1Ih .node ellipse,#mermaid-svg-JntSAx2HBOrWO1Ih .node polygon,#mermaid-svg-JntSAx2HBOrWO1Ih .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JntSAx2HBOrWO1Ih .rough-node .label text,#mermaid-svg-JntSAx2HBOrWO1Ih .node .label text,#mermaid-svg-JntSAx2HBOrWO1Ih .image-shape .label,#mermaid-svg-JntSAx2HBOrWO1Ih .icon-shape .label{text-anchor:middle;}#mermaid-svg-JntSAx2HBOrWO1Ih .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JntSAx2HBOrWO1Ih .rough-node .label,#mermaid-svg-JntSAx2HBOrWO1Ih .node .label,#mermaid-svg-JntSAx2HBOrWO1Ih .image-shape .label,#mermaid-svg-JntSAx2HBOrWO1Ih .icon-shape .label{text-align:center;}#mermaid-svg-JntSAx2HBOrWO1Ih .node.clickable{cursor:pointer;}#mermaid-svg-JntSAx2HBOrWO1Ih .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JntSAx2HBOrWO1Ih .arrowheadPath{fill:#333333;}#mermaid-svg-JntSAx2HBOrWO1Ih .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JntSAx2HBOrWO1Ih .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JntSAx2HBOrWO1Ih .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JntSAx2HBOrWO1Ih .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JntSAx2HBOrWO1Ih .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JntSAx2HBOrWO1Ih .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JntSAx2HBOrWO1Ih .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JntSAx2HBOrWO1Ih .cluster text{fill:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih .cluster span{color:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JntSAx2HBOrWO1Ih .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JntSAx2HBOrWO1Ih rect.text{fill:none;stroke-width:0;}#mermaid-svg-JntSAx2HBOrWO1Ih .icon-shape,#mermaid-svg-JntSAx2HBOrWO1Ih .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JntSAx2HBOrWO1Ih .icon-shape p,#mermaid-svg-JntSAx2HBOrWO1Ih .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JntSAx2HBOrWO1Ih .icon-shape rect,#mermaid-svg-JntSAx2HBOrWO1Ih .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JntSAx2HBOrWO1Ih .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JntSAx2HBOrWO1Ih .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JntSAx2HBOrWO1Ih :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
原始CSV数据
数据建模
user_info 用户表id / age_range / gender
user_log 行为日志表user_id / item_id / cat_idseller_id / brand_id / time_stamp / action_type
LOAD DATA 导入Hive
基础统计查询
用户总数: 424,170
购买记录: 54,925,330
卖家数量: 4,995
热门分析
热卖商品 Top10DISTRIBUTE BY + SORT BY
热卖品牌 Top10
购买力用户 Top50
用户画像分析
性别 vs 购买行为LEFT JOIN + 内存调优
年龄 vs 购买行为各年龄段消费力对比
时间趋势分析
时间戳转换from_unixtime
按天/按时消费趋势
高级分析
回购率 Top10 品牌
每品牌销量 Top3 商品ROW_NUMBER() OVER()
1.3 前置知识要求
| Hive基础 | 建表、分区、数据类型 | ⭐⭐⭐⭐⭐ |
| Hadoop | HDFS 文件系统、MapReduce 原理 | ⭐⭐⭐⭐ |
| SQL | GROUP BY、JOIN、子查询 | ⭐⭐⭐⭐ |
| 窗口函数 | ROW_NUMBER() OVER(PARTITION BY) | ⭐⭐⭐ |
| Linux | 集群管理、配置文件修改 | ⭐⭐⭐ |
| 性能调优 | YARN 内存配置、分布式计算 | ⭐⭐⭐ |
二、数据建模与导入
2.1 数据集说明
本项目使用两份数据文件:
| user_info_format1.csv | 用户信息表 | user_id, age_range, gender | ~42.4万 |
| user_log_format1.csv | 购买行为日志 | user_id, item_id, cat_id, seller_id, brand_id, time_stamp, action_type | ~5492万 |
2.2 建表语句
用户信息表
— 创建用户信息表,存储用户基本属性
CREATE TABLE user_info (
id INT COMMENT '唯一标识用户ID',
age_range INT COMMENT '年龄范围:0-8表示不同年龄段',
gender INT COMMENT '性别:0-女, 1-男, 2-保密'
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\\n';
用户行为日志表
— 创建用户购买行为日志表,记录每次购买行为
CREATE TABLE user_log (
user_id INT COMMENT '买家ID',
item_id INT COMMENT '商品ID',
cat_id INT COMMENT '商品分类ID',
seller_id INT COMMENT '卖家ID',
brand_id INT COMMENT '品牌ID',
time_stamp BIGINT COMMENT '购买时间戳',
action_type INT COMMENT '行为类型'
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\\n';
⚠️ 踩坑提示:CSV 文件首行是列名标题行,LOAD DATA 时会被当作数据行导入,后续查询时需注意过滤 NULL 值。
2.3 启动集群并导入数据
# Step 1: node1 上启动 Hadoop 集群
startha.sh
# Step 2: node3 上启动 Hive 客户端(打印表头)
hive –hiveconf hive.cli.print.header=true
# Step 3: 使用 xftp 上传 CSV 文件到 node3 的 /root 目录
— Step 4: 导入用户信息数据
LOAD DATA LOCAL INPATH '/root/user_info_format1.csv'
INTO TABLE user_info;
— 耗时: 2.853 秒
— Step 5: 导入购买日志数据
LOAD DATA LOCAL INPATH '/root/user_log_format1.csv'
INTO TABLE user_log;
— 耗时: 154.761 秒(数据量较大)
三、基础统计分析
3.1 查询用户总数
— 统计用户总量
SELECT COUNT(id) FROM user_info;
| COUNT(id) | 424,171 | 含标题行 |
| COUNT(id) WHERE id IS NOT NULL | 424,170 | 过滤后真实用户数 |
💡 建议:生产环境中务必加上 WHERE id IS NOT NULL 过滤条件,避免标题行污染统计数据。
3.2 查询购买记录总数
— 统计购买行为总记录数
SELECT COUNT(user_id) AS log_num
FROM user_log
WHERE user_id IS NOT NULL;
| 购买记录总数 | 54,925,330 |
| 查询耗时 | 181.301 秒 |
3.3 查询卖家总数
— 使用子查询去重统计卖家数量
SELECT COUNT(seller_id)
FROM (
SELECT seller_id
FROM user_log
GROUP BY seller_id
) tmp;
| 卖家总数 | 4,995 |
| 查询耗时 | 111.301 秒 |
四、热门商品与品牌分析
4.1 热卖商品 Top10
⚠️ 错误案例一:ORDER BY 导致单 Reduce 瓶颈
错误做法:
— ❌ 错误:在大数据量下使用 ORDER BY 全局排序
— 所有数据汇聚到单个 Reduce,导致任务失败或极慢
SELECT item_id, COUNT(user_id) AS num
FROM user_log
GROUP BY item_id
ORDER BY num DESC
LIMIT 10;
问题分析:ORDER BY 会将所有数据发送到 一个 Reduce 进行全局排序。当数据量达到 5492 万条时,单个 Reduce 节点可能因内存不足而失败,即使成功也需要极长时间。
解决方案:
— ✅ 正确:使用 DISTRIBUTE BY + SORT BY 分布式排序
— DISTRIBUTE BY num: 按 num 哈希分布到多个 Reduce
— SORT BY num DESC: 每个 Reduce 内部降序排列
SELECT item_id, COUNT(user_id) AS num
FROM user_log
WHERE user_id IS NOT NULL
GROUP BY item_id
DISTRIBUTE BY num
SORT BY num DESC
LIMIT 10;
查询结果:
| 1 | 67897 | 345,905 |
| 2 | 783997 | 178,005 |
| 3 | 636863 | 82,480 |
| 4 | 631714 | 42,771 |
| 5 | 61518 | 34,801 |
| 6 | 559967 | 28,816 |
| 7 | 770668 | 28,431 |
| 8 | 94609 | 23,027 |
| 9 | 1059899 | 22,242 |
| 10 | 1024557 | 21,045 |
🕐 查询耗时: 184.565 秒
4.2 热卖品牌 Top10
— 查询销量最高的前10个品牌
SELECT brand_id, COUNT(item_id) AS num
FROM user_log
WHERE brand_id IS NOT NULL
GROUP BY brand_id
DISTRIBUTE BY num
SORT BY num DESC
LIMIT 10;
| 1 | 3738 | 763,345 |
| 2 | 1360 | 737,545 |
| 3 | 1446 | 729,555 |
| 4 | 1214 | 541,075 |
| 5 | 5376 | 528,003 |
| 6 | 82 | 503,911 |
| 7 | 2276 | 491,738 |
| 8 | 8235 | 400,024 |
| 9 | 4705 | 363,417 |
| 10 | 1662 | 332,633 |
🕐 查询耗时: 307.704 秒
洞察:品牌 3738、1360、1446 三足鼎立,合计销量超过 223 万,占总销量的比例极高,头部效应明显。
4.3 购买力最强用户 Top50
— 查询购买商品数量最多的前50名用户
SELECT user_id, COUNT(item_id) AS num
FROM user_log
WHERE user_id IS NOT NULL
GROUP BY user_id
DISTRIBUTE BY num
SORT BY num DESC
LIMIT 50;
| 1 | 254263 | 14,468 |
| 2 | 276887 | 11,856 |
| 3 | 109251 | 9,173 |
| 4 | 23106 | 8,370 |
| 5 | 179074 | 8,161 |
🕐 查询耗时: 207.172 秒
五、时间维度消费趋势分析
5.1 不同时间戳的消费分布
— 使用 CLUSTER BY 简化 DISTRIBUTE BY + SORT BY 同字段场景
— CLUSTER BY = DISTRIBUTE BY + SORT BY(仅支持升序)
SELECT time_stamp, COUNT(item_id) AS num
FROM user_log
WHERE time_stamp IS NOT NULL
GROUP BY time_stamp
CLUSTER BY time_stamp;
💡 技巧:当 DISTRIBUTE BY 和 SORT BY 的字段相同时,可以用 CLUSTER BY 简化语法。但注意 CLUSTER BY 只能升序排列。
5.2 时间戳转换:按天分析趋势
— 将毫秒级时间戳转换为日期格式,按天统计消费趋势
SELECT
from_unixtime(CAST(time_stamp/1000 AS BIGINT), 'yyyy-MM-dd') AS dt,
COUNT(item_id) AS num
FROM user_log
WHERE time_stamp IS NOT NULL
GROUP BY from_unixtime(CAST(time_stamp/1000 AS BIGINT), 'yyyy-MM-dd')
CLUSTER BY time_stamp;
5.3 指定时间段消费趋势
— 分析 2030年3月30日至6月30日期间的消费趋势
SELECT
from_unixtime(CAST(time_stamp/1000 AS BIGINT), 'yyyy-MM-dd') AS dt,
COUNT(item_id) AS num
FROM user_log
WHERE time_stamp IS NOT NULL
AND time_stamp >= unix_timestamp('2030-03-30', 'yyyy-MM-dd') * 1000
AND time_stamp < unix_timestamp('2030-06-30', 'yyyy-MM-dd') * 1000
GROUP BY from_unixtime(CAST(time_stamp/1000 AS BIGINT), 'yyyy-MM-dd')
CLUSTER BY time_stamp;
六、回购率与用户画像分析
6.1 回购率排名 Top10 品牌
— 查询每个用户在每个品牌下的购买次数,取回购最高的Top10
SELECT user_id, brand_id, COUNT(item_id) AS num
FROM user_log
WHERE user_id IS NOT NULL
AND brand_id IS NOT NULL
GROUP BY user_id, brand_id
DISTRIBUTE BY num
SORT BY num DESC
LIMIT 10;
| 1 | 254263 | 1214 | 7,688 |
| 2 | 112081 | 1360 | 6,962 |
| 3 | 349577 | 1360 | 4,707 |
| 4 | 361341 | 99 | 4,434 |
| 5 | 269579 | 1446 | 4,219 |
🕐 查询耗时: 425.305 秒(3 个 MapReduce Job)
6.2 性别维度消费行为分析
⚠️ 错误案例二:LEFT JOIN 内存溢出
错误现象:
— 该查询因 YARN 内存不足而报错
SELECT u.gender, COUNT(g.item_id) AS num
FROM user_info u
LEFT JOIN user_log g ON u.id = g.user_id
WHERE g.user_id IS NOT NULL
GROUP BY u.gender
DISTRIBUTE BY num
SORT BY num DESC;
报错信息:
FAILED: Execution Error, return code 3 from
org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask
问题分析:LEFT JOIN 两张表(42万 × 5492万),Map Join 阶段需要将小表加载到内存,默认 YARN 分配内存(512MB-1024MB)不足以处理此规模的 JOIN 操作。
解决方案:
Step 1:修改 YARN 配置文件 yarn-site.xml
<!– 调整前 –>
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>512</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>1024</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>1024</value>
</property>
<!– 调整后 –>
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>1024</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>2048</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>2048</value>
</property>
Step 2:分发配置到所有节点并重启集群
# 将修改后的配置文件分发到 node1、node2、node4
cd /opt/hadoop-3.1.3/etc/hadoop
scp yarn-site.xml node1:`pwd`
scp yarn-site.xml node2:`pwd`
scp yarn-site.xml node4:`pwd`
# 重启集群
# node1: startha.sh
# node3: hive –hiveconf hive.cli.print.header=true
Step 3:重新执行查询
SELECT u.gender, COUNT(g.item_id) AS num
FROM user_info u
LEFT JOIN user_log g ON u.id = g.user_id
WHERE g.user_id IS NOT NULL
GROUP BY u.gender
DISTRIBUTE BY num
SORT BY num DESC;
查询结果:
| 0(女) | 40,313,178 | 73.5% | 女性是消费主力 |
| 1(男) | 12,135,530 | 22.1% | 男性消费约为女性的 1/3 |
| 2(保密) | 2,055,127 | 3.7% | 未透露性别用户 |
| NULL | 421,495 | 0.8% | 脏数据 |
🕐 查询耗时: 466.755 秒
核心洞察:女性用户贡献了 73.5% 的购买量,是绝对消费主力。电商平台的运营策略应重点向女性用户倾斜。
6.3 年龄维度消费行为分析
— 分析各年龄段的消费行为差异
SELECT u.age_range, COUNT(g.item_id) AS num
FROM user_info u
LEFT JOIN user_log g ON u.id = g.user_id
WHERE g.user_id IS NOT NULL
GROUP BY u.age_range
DISTRIBUTE BY num
SORT BY num DESC
LIMIT 10;
| 1 | 3 | 14,848,637 |
| 2 | 4 | 11,802,052 |
| 3 | 0 | 9,931,162 |
| 4 | 5 | 6,200,000 |
| 5 | 6 | 5,413,716 |
| 6 | 2 | 5,385,020 |
| 7 | 7 | 1,052,265 |
| 8 | 8 | 162,534 |
| 9 | 1 | 1,721 |
🕐 查询耗时: 441.976 秒
七、窗口函数高级分析:每品牌销量 Top3 商品
7.1 分步拆解
步骤一:统计每个品牌下每个商品的销量
— 基础聚合,查看每个品牌每个商品的销售数量
SELECT brand_id, item_id, COUNT(user_id) AS number
FROM user_log
WHERE brand_id IS NOT NULL
AND item_id IS NOT NULL
GROUP BY brand_id, item_id
LIMIT 30;
步骤二:按品牌分组聚类
— 使用 CLUSTER BY 将相同品牌的数据聚合到一起
SELECT brand_id, item_id, COUNT(user_id) AS number
FROM user_log
WHERE brand_id IS NOT NULL
AND item_id IS NOT NULL
GROUP BY brand_id, item_id
CLUSTER BY brand_id
LIMIT 30;
步骤三:使用 ROW_NUMBER() 窗口函数排名
— 终极SQL:每个品牌下销量前3的商品
— 使用 ROW_NUMBER() 窗口函数按品牌分区、按销量降序排名
SELECT brand_id, item_id, number, rk
FROM (
SELECT brand_id, item_id, number,
ROW_NUMBER() OVER(PARTITION BY brand_id ORDER BY number DESC) AS rk
FROM (
SELECT brand_id, item_id, COUNT(user_id) AS number
FROM user_log
WHERE brand_id IS NOT NULL
AND item_id IS NOT NULL
GROUP BY brand_id, item_id
CLUSTER BY brand_id
) tba
) tbb
WHERE tbb.rk <= 3;
查询结果示例:
| 8475 | 103981 | 23 | 1 |
| 8475 | 977504 | 20 | 2 |
| 8475 | 752808 | 8 | 3 |
| 8476 | 38860 | 1916 | 1 |
| 8476 | 871890 | 1427 | 2 |
| 8476 | 1054 | 793 | 3 |
7.2 窗口函数原理图解
#mermaid-svg-BbKHdbyIWdjgUjAK{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BbKHdbyIWdjgUjAK .error-icon{fill:#552222;}#mermaid-svg-BbKHdbyIWdjgUjAK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BbKHdbyIWdjgUjAK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BbKHdbyIWdjgUjAK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BbKHdbyIWdjgUjAK .marker.cross{stroke:#333333;}#mermaid-svg-BbKHdbyIWdjgUjAK svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BbKHdbyIWdjgUjAK p{margin:0;}#mermaid-svg-BbKHdbyIWdjgUjAK .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK .cluster-label text{fill:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK .cluster-label span{color:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK .cluster-label span p{background-color:transparent;}#mermaid-svg-BbKHdbyIWdjgUjAK .label text,#mermaid-svg-BbKHdbyIWdjgUjAK span{fill:#333;color:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK .node rect,#mermaid-svg-BbKHdbyIWdjgUjAK .node circle,#mermaid-svg-BbKHdbyIWdjgUjAK .node ellipse,#mermaid-svg-BbKHdbyIWdjgUjAK .node polygon,#mermaid-svg-BbKHdbyIWdjgUjAK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BbKHdbyIWdjgUjAK .rough-node .label text,#mermaid-svg-BbKHdbyIWdjgUjAK .node .label text,#mermaid-svg-BbKHdbyIWdjgUjAK .image-shape .label,#mermaid-svg-BbKHdbyIWdjgUjAK .icon-shape .label{text-anchor:middle;}#mermaid-svg-BbKHdbyIWdjgUjAK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BbKHdbyIWdjgUjAK .rough-node .label,#mermaid-svg-BbKHdbyIWdjgUjAK .node .label,#mermaid-svg-BbKHdbyIWdjgUjAK .image-shape .label,#mermaid-svg-BbKHdbyIWdjgUjAK .icon-shape .label{text-align:center;}#mermaid-svg-BbKHdbyIWdjgUjAK .node.clickable{cursor:pointer;}#mermaid-svg-BbKHdbyIWdjgUjAK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BbKHdbyIWdjgUjAK .arrowheadPath{fill:#333333;}#mermaid-svg-BbKHdbyIWdjgUjAK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BbKHdbyIWdjgUjAK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BbKHdbyIWdjgUjAK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BbKHdbyIWdjgUjAK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BbKHdbyIWdjgUjAK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BbKHdbyIWdjgUjAK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BbKHdbyIWdjgUjAK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BbKHdbyIWdjgUjAK .cluster text{fill:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK .cluster span{color:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BbKHdbyIWdjgUjAK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BbKHdbyIWdjgUjAK rect.text{fill:none;stroke-width:0;}#mermaid-svg-BbKHdbyIWdjgUjAK .icon-shape,#mermaid-svg-BbKHdbyIWdjgUjAK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BbKHdbyIWdjgUjAK .icon-shape p,#mermaid-svg-BbKHdbyIWdjgUjAK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BbKHdbyIWdjgUjAK .icon-shape rect,#mermaid-svg-BbKHdbyIWdjgUjAK .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BbKHdbyIWdjgUjAK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BbKHdbyIWdjgUjAK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BbKHdbyIWdjgUjAK :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
原始数据brand_id, item_id, number
PARTITION BY brand_id按品牌分组
品牌 8475103981: 23977504: 20752808: 8
品牌 847638860: 1916871890: 14271054: 793
ORDER BY number DESC组内降序
ROW_NUMBER()从1开始编号
WHERE rk <= 3取前三
八、性能优化总结
8.1 SQL 优化对照表
| 大数据量排序 | ORDER BY | DISTRIBUTE BY + SORT BY | 避免单Reduce瓶颈 |
| 同字段分布+排序 | DISTRIBUTE BY x SORT BY x | CLUSTER BY x | 语法更简洁 |
| LEFT JOIN 大表 | 默认YARN配置 | 调大内存至2048MB | 防止Map Join OOM |
| 数据导入 | 不处理标题行 | 查询时加 IS NOT NULL | 过滤脏数据 |
8.2 各查询性能对比
| 用户总数 | 62 | 42万 | 1 |
| 购买记录总数 | 181 | 5492万 | 1 |
| 热卖商品Top10 | 185 | 5492万 | 2 |
| 热卖品牌Top10 | 308 | 5492万 | 2 |
| 购买力Top50用户 | 207 | 5492万 | 2 |
| 回购率Top10 | 425 | 5492万 | 3 |
| 性别分析 | 467 | JOIN | 2 |
| 年龄分析 | 442 | JOIN | 2 |
| 品牌Top3商品 | 122 | 5492万 | 2 |
九、总结与展望
9.1 本文核心收获
9.2 扩展方向
- 使用 Spark SQL 替代 Hive,利用内存计算加速查询(预计可提速 5-10 倍)
- 引入 RFM 模型(最近消费、频率、金额)进行用户分层
- 搭建 数据可视化大屏(ECharts/Superset),直观展示分析结果
- 基于购买行为数据构建 推荐系统(协同过滤 / 关联规则挖掘)
9.3 下一篇预告
下一篇我们将进入电影数据分析项目,使用 Python + Pandas + Matplotlib 对百万级电影评分数据进行探索性分析(EDA),挖掘高分电影的特征规律。敬请期待!🚀
参考链接
📝 声明:本文数据来源于公开的电商用户行为数据集,仅用于学习和技术交流目的。文中涉及的所有 SQL 语句均在 Hive 3.1.3 + Hadoop 3.1.3 环境下验证通过。
🏷️ 标签:#Hive #大数据 #电商分析 #SQL优化 #Hadoop #窗口函数



