🍋🍋大数据学习🍋🍋
🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。
💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博主哦🤞
一、连续值问题(如连续登录、连续消费)
核心思路:
- 生成连续标识:通过
日期 - 行号
生成分组标识,连续日期的该值相同。 - 分组统计:按标识分组,统计连续长度。
典型例题:
计算连续登录超过 7 天的用户 ID。
代码模板:
WITH user_dates AS (
-- 去重并生成行号
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM (
SELECT DISTINCT user_id, login_date
FROM user_login
) t
),
date_groups AS (
-- 生成连续标识
SELECT
user_id,
login_date,
DATE_SUB(login_date, rn) AS date_group
FROM user_dates
)
-- 筛选连续≥7天的用户
SELECT
user_id,
MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS consecutive_days
FROM date_groups
GROUP BY user_id, date_group
HAVING COUNT(*) >= 7;
二、Top N 问题(如每个分组的前 N 条)
核心思路:
- 窗口函数排名:用
ROW_NUMBER()
/RANK()
/DENSE_RANK()
生成排名。 - 过滤结果:筛选排名 ≤N 的记录。
典型例题:
查询每个部门薪资最高的前 3 名员工。
代码模板:
WITH ranked_employees AS (
SELECT
dept_id,
emp_id,
salary,
ROW_NUMBER() OVER (
PARTITION BY dept_id
ORDER BY salary DESC
) AS rank
FROM employees
)
SELECT *
FROM ranked_employees
WHERE rank <= 3;
三、时间窗口计算(同比 / 环比 / 移动平均)
核心思路:
- 关联历史数据:用
JOIN
或窗口函数LAG()
获取历史值。 - 计算差值 / 比例:如
(当前值 - 历史值)/历史值
。
典型例题:
计算每月销售额的环比增长率。
代码模板:
WITH monthly_sales AS (
SELECT
YEAR(sale_date) AS sale_year,
MONTH(sale_date) AS sale_month,
SUM(amount) AS total_amount
FROM sales
GROUP BY YEAR(sale_date), MONTH(sale_date)
)
SELECT
curr.sale_year,
curr.sale_month,
curr.total_amount,
prev.total_amount AS prev_month_amount,
(curr.total_amount - prev.total_amount) / prev.total_amount AS mom_growth
FROM monthly_sales curr
LEFT JOIN monthly_sales prev
ON curr.sale_month = prev.sale_month + 1
AND curr.sale_year = prev.sale_year;
四、留存分析(N 日留存率)
核心思路:
- 标记首次行为:用
MIN()
确定用户首次登录 / 注册日期。 - 关联后续行为:用
JOIN
或窗口函数判断是否在 N 日后仍活跃。
典型例题:
计算 2023 年 1 月每日新增用户的 7 日留存率。
代码模板:
WITH first_login AS (
SELECT
user_id,
MIN(login_date) AS first_date
FROM user_login
WHERE login_date >= '2023-01-01' AND login_date <= '2023-01-24'
GROUP BY user_id
)
SELECT
fl.first_date,
COUNT(DISTINCT fl.user_id) AS new_users,
COUNT(DISTINCT ul.user_id) AS retained_users,
COUNT(DISTINCT ul.user_id) / COUNT(DISTINCT fl.user_id) AS retention_rate_7d
FROM first_login fl
LEFT JOIN user_login ul
ON fl.user_id = ul.user_id
AND ul.login_date = DATE_ADD(fl.first_date, 7)
GROUP BY fl.first_date;
五、多表关联优化(大表 JOIN)
核心思路:
- 过滤数据:在 JOIN 前用
WHERE
减少数据量。 - 使用 MapJoin:小表放右侧,触发 Map 端 JOIN。
- 分桶表优化:按 JOIN 字段分桶,提高数据分布均匀性。
典型例题:
优化 orders
(亿级)和 customers
(百万级)的 JOIN。
代码模板:
-- 方法1:手动 MapJoin(Hive 3.0+ 自动优化)
SELECT /*+ MAPJOIN(c) */
o.order_id,
c.customer_name
FROM orders o
JOIN customers c
ON o.customer_id = c.customer_id
WHERE o.order_date >= '2023-01-01';
-- 方法2:分桶表优化
SET hive.optimize.skewjoin=true;
SELECT
o.order_id,
c.customer_name
FROM orders_bucketed o
JOIN customers_bucketed c
ON o.customer_id = c.customer_id;
六、数据倾斜处理
核心思路:
- 拆分热点值:对高频 key 添加随机前缀,分两阶段聚合。
- 过滤异常值:排除导致倾斜的无效数据。
- 调整参数:增大
hive.groupby.skewindata
。
典型例题:
优化 GROUP BY user_id
时的倾斜问题。
代码模板:
-- 两阶段聚合
WITH stage1 AS (
SELECT
CONCAT(user_id, '_', FLOOR(RAND() * 10)) AS tmp_key,
COUNT(*) AS cnt
FROM logs
GROUP BY CONCAT(user_id, '_', FLOOR(RAND() * 10))
)
SELECT
SPLIT(tmp_key, '_')[0] AS user_id,
SUM(cnt) AS total_cnt
FROM stage1
GROUP BY SPLIT(tmp_key, '_')[0];
七、JSON / 复杂类型处理
核心思路:
- 解析 JSON:用
get_json_object()
或json_tuple()
提取字段。 - 展开数组:用
LATERAL VIEW explode()
展开数组元素。
典型例题:
解析 user_info
表中的 tags
字段(JSON 数组)。
代码模板:
-- 解析 JSON 数组
SELECT
user_id,
tag
FROM user_info
LATERAL VIEW explode(
split(regexp_replace(tags, '[\\[\\]" ]', ''), ',')
) t AS tag;
-- 提取 JSON 对象字段
SELECT
user_id,
get_json_object(user_info, '$.name') AS name,
get_json_object(user_info, '$.age') AS age
FROM user_info;
八、累计计算(累计和、累计占比)
核心思路:
- 窗口函数:用
SUM() OVER (ORDER BY ...)
实现累计聚合。 - 排序规则:确保
ORDER BY
与业务逻辑一致。
典型例题:
计算每月累计销售额及累计占比。
代码模板:
WITH monthly_sales AS (
SELECT
YEAR(sale_date) AS sale_year,
MONTH(sale_date) AS sale_month,
SUM(amount) AS monthly_amount
FROM sales
GROUP BY YEAR(sale_date), MONTH(sale_date)
)
SELECT
sale_year,
sale_month,
monthly_amount,
SUM(monthly_amount) OVER (
PARTITION BY sale_year
ORDER BY sale_month
) AS cumulative_amount,
SUM(monthly_amount) OVER (
PARTITION BY sale_year
ORDER BY sale_month
) / SUM(monthly_amount) OVER (PARTITION BY sale_year) AS cumulative_ratio
FROM monthly_sales;
九、缺失值填充(连续日期补全)
核心思路:
- 生成完整日期序列:用
LATERAL VIEW
和SEQUENCE
函数。 - 左连接原数据:用
COALESCE()
填充缺失值。
典型例题:
补全用户每日登录记录(无登录日填充为 0)。
代码模板:
WITH all_dates AS (
SELECT
user_id,
DATE_ADD('2023-01-01', pos) AS login_date
FROM (
SELECT DISTINCT user_id FROM user_login
) u
LATERAL VIEW posexplode(
split(repeat('1', DATEDIFF('2023-01-31', '2023-01-01')), '1')
) t AS pos, val
)
SELECT
ad.user_id,
ad.login_date,
COALESCE(ul.login_count, 0) AS login_count
FROM all_dates ad
LEFT JOIN (
SELECT
user_id,
login_date,
COUNT(*) AS login_count
FROM user_login
GROUP BY user_id, login_date
) ul
ON ad.user_id = ul.user_id AND ad.login_date = ul.login_date;
十、异常值检测(离群点识别)
核心思路:
- 计算统计指标:如均值、标准差。
- 定义阈值:如
|值 - 均值| > 3*标准差
。
典型例题:
找出订单金额异常高的记录。
代码模板:
WITH order_stats AS (
SELECT
AVG(amount) AS avg_amount,
STDDEV(amount) AS std_amount
FROM orders
)
SELECT
o.order_id,
o.amount
FROM orders o
CROSS JOIN order_stats s
WHERE ABS(o.amount - s.avg_amount) > 3 * s.std_amount;
总结
- 明确业务需求:确定输入输出,如 “连续登录”“留存率”。
- 设计数据模型:分析涉及的表、关联字段和聚合维度。
- 选择技术方案:套用上述思路(如连续值用
日期-行号
,Top N 用ROW_NUMBER
)。 - 分步实现:先写基础查询,再叠加窗口函数和优化逻辑。
- 验证结果:用小规模数据测试,检查边界条件(如空值、单条记录)。