SQL 搜索日志热门TopN查询词:GROUP BY + ORDER BY + LIMIT(百度面试题)
一、题目
现有一张搜索日志表 t5_search_log,记录了用户每次搜索的查询词。请统计搜索次数最多的前10个查询词(Top 10热门搜索词)。
搜索日志表 t5_search_log:
+----------+-------------+----------------------+
| user_id | query_word | search_time |
+----------+-------------+----------------------+
| u01 | 天气预报 | 2023-03-01 08:00:00 |
| u02 | 股票行情 | 2023-03-01 08:05:00 |
| u01 | 百度地图 | 2023-03-01 09:00:00 |
| u03 | 天气预报 | 2023-03-01 09:10:00 |
| u04 | 世界杯 | 2023-03-01 09:15:00 |
| u02 | 天气预报 | 2023-03-01 09:20:00 |
| u05 | 高考成绩 | 2023-03-01 10:00:00 |
| u01 | 股票行情 | 2023-03-01 10:30:00 |
| u03 | 百度地图 | 2023-03-01 11:00:00 |
| u04 | 天气预报 | 2023-03-01 11:30:00 |
| u06 | 深度学习 | 2023-03-01 12:00:00 |
| u07 | 天气预报 | 2023-03-01 12:30:00 |
| u08 | ChatGPT | 2023-03-01 13:00:00 |
| u05 | 世界杯 | 2023-03-01 14:00:00 |
| u06 | 百度地图 | 2023-03-01 15:00:00 |
+----------+-------------+----------------------+
二、思路分析
本题是最基础的聚合排序题,考察 GROUP BY + ORDER BY + LIMIT:
- 分组统计:
GROUP BY query_word按查询词分组,COUNT(1)统计搜索次数 - 降序排列:
ORDER BY search_cnt DESC按搜索次数从高到低 - 取前N条:
LIMIT 10取出排名前10的热门词
| 维度 | 评分 |
|---|---|
| 题目难度 | ⭐️ |
| 题目清晰度 | ⭐️⭐️⭐️⭐️⭐️ |
| 业务常见度 | ⭐️⭐️⭐️⭐️⭐️ |
三、逐步推导
统计热门搜索词Top 10
一道查询即可完成:按查询词分组→统计次数→降序→取前10。
执行SQL
select query_word,
count(1) as search_cnt
from t5_search_log
group by query_word
order by search_cnt desc
limit 10
执行结果
+-------------+-------------+
| query_word | search_cnt |
+-------------+-------------+
| 天气预报 | 5 |
| 百度地图 | 3 |
| 股票行情 | 2 |
| 世界杯 | 2 |
| 高考成绩 | 1 |
| ChatGPT | 1 |
| 深度学习 | 1 |
+-------------+-------------+
7 rows selected (8.319 seconds)(https://www.dwsql.com)
四、常见坑点
坑1:COUNT vs COUNT DISTINCT 的选择
如果同一个用户多次搜索同一个词(如 u01 搜了两次"天气预报"),用 COUNT(1) 算的是搜索次数,用 COUNT(DISTINCT user_id) 算的是搜索人数。本题目的是"热门搜索词"应该算次数,所以用 COUNT(1)。
坑2:数据倾斜导致部分Reducer过载
搜索日志中热门词(如"天气预报")的搜索量可能是长尾词的数万倍。GROUP BY query_word 时,热门词所在的Reducer处理的数据量远大于其他Reducer,形成数据倾斜——绝大多数任务已完成,只有1-2个Reducer在"卡住"。
Spark SQL 的应对方案:
- 开启AQE自适应优化:
spark.sql.adaptive.enabled = true,Spark 3.0+ 的AQE会自动检测倾斜分区并拆分为多个子任务并行处理 - 两阶段聚合(加盐法):先给热点key加随机后缀(如
concat(query_word, '_', floor(rand()*10)))做局部预聚合,再去掉后缀做最终聚合。两次GROUP BY虽然多了一次Shuffle,但避免了单点瓶颈 - 调整shuffle分区数:增大
spark.sql.shuffle.partitions(默认200),让每个Reducer处理更少的数据
面试中主动讨论数据倾斜,展示工程经验会显著加分。
坑3:LIMIT 的方言差异
LIMIT 10 在 Hive/Spark/MySQL 通用。SQL Server 用 SELECT TOP 10,Oracle 用 WHERE ROWNUM <= 10。面试时注明你用的SQL方言即可。
五、知识点总结
| 考点 | 说明 |
|---|---|
| GROUP BY + COUNT | 按查询词聚合,统计每个词的搜索频率 |
| ORDER BY DESC | 降序排列,热度最高的排最前面 |
| LIMIT N | 取前N条记录,实现Top N效果 |
六、建表语句和数据插入
点击展开 DDL & DML
create table t5_search_log (
user_id string COMMENT '用户ID',
query_word string COMMENT '查询词',
search_time string COMMENT '搜索时间'
) COMMENT '搜索日志表';
insert into t5_search_log values
('u01', '天气预报', '2023-03-01 08:00:00'),
('u02', '股票行情', '2023-03-01 08:05:00'),
('u01', '百度地图', '2023-03-01 09:00:00'),
('u03', '天气预报', '2023-03-01 09:10:00'),
('u04', '世界杯', '2023-03-01 09:15:00'),
('u02', '天气预报', '2023-03-01 09:20:00'),
('u05', '高考成绩', '2023-03-01 10:00:00'),
('u01', '股票行情', '2023-03-01 10:30:00'),
('u03', '百度地图', '2023-03-01 11:00:00'),
('u04', '天气预报', '2023-03-01 11:30:00'),
('u06', '深度学习', '2023-03-01 12:00:00'),
('u07', '天气预报', '2023-03-01 12:30:00'),
('u08', 'ChatGPT', '2023-03-01 13:00:00'),
('u05', '世界杯', '2023-03-01 14:00:00'),
('u06', '百度地图', '2023-03-01 15:00:00');
📱关注公众号
「数据仓库技术」文章同步更新,不错过每一篇干货

💬加群交流
备注「数据仓库技术」加入社群,每日一道大厂SQL真题
