Hive的窗口函数

Hive的窗口函数(Window Functions)是其SQL功能的核心亮点之一,用于在分组数据上执行计算,同时保留原始表的行数(不压缩分组)。窗口函数特别适用于排名分析趋势计算移动统计等复杂场景,是处理时间序列数据和多维分析的利器。

一、窗口函数的核心概念

窗口函数的语法结构:

sql 复制代码
function_name(arg1, arg2...) OVER (
  [PARTITION BY col1, col2...]  -- 分组(类似GROUP BY,但不压缩行数)
  [ORDER BY col3, col4...]      -- 排序(决定窗口内数据的处理顺序)
  [ROWS/RANGE BETWEEN ... AND ...]  -- 窗口范围(可选,定义当前行的关联行)
)
关键组件解析:
  1. 函数部分

    • 聚合函数 :如sum()avg()count(),在窗口内执行聚合。
    • 排序函数 :如row_number()rank(),生成排名。
    • 分析函数 :如lead()lag(),获取前后行数据。
  2. OVER子句

    • PARTITION BY:将数据按指定列分组,窗口函数在每个分组内独立计算。
    • ORDER BY:定义窗口内数据的排序规则,影响函数计算顺序(如累加方向)。
    • 窗口框架(Window Frame)
      • ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:从分组首行到当前行。
      • ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING:当前行的前1行到后1行(共3行)。

二、窗口函数的分类与应用场景

1. 排名函数

row_number()

  • 功能:为窗口内的每行分配唯一序号(1,2,3...),无重复值。
  • 应用 :分组内TopN筛选(如每个用户的最近订单)。
    示例
sql 复制代码
SELECT 
  user_id, 
  order_time, 
  row_number() OVER (
    PARTITION BY user_id 
    ORDER BY order_time DESC  -- 按订单时间倒序
  ) AS rn
FROM orders;
-- rn=1即为每个用户的最近订单

rank() vs dense_rank()

  • 区别
    • rank():相同值排名相同,后续排名跳号(如1,1,3)。
    • dense_rank():相同值排名相同,后续排名不跳号(如1,1,2)。
      示例
sql 复制代码
SELECT 
  score,
  rank() OVER (ORDER BY score DESC) AS rk,
  dense_rank() OVER (ORDER BY score DESC) AS drk
FROM students;
-- 若score有两个85分,rk为1,1,3;drk为1,1,2
2. 聚合函数(窗口聚合)

sum() / avg() / count()

  • 功能:在窗口内执行累加、平均、计数,不压缩行数。
  • 应用 :计算累计销售额、移动平均。
    示例
sql 复制代码
SELECT 
  order_date, 
  amount,
  sum(amount) OVER (
    ORDER BY order_date 
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW  -- 累计到当前行
  ) AS cumulative_sum,
  avg(amount) OVER (
    ORDER BY order_date 
    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW  -- 近3天移动平均
  ) AS moving_avg
FROM daily_orders;
3. 分析函数

lead(col, n) / lag(col, n)

  • 功能 :获取当前行的前n行(lag)或后n行(lead)数据。
  • 应用 :计算环比(如次日与当日的差值)。
    示例
sql 复制代码
SELECT 
  date, 
  sales,
  lag(sales, 1) OVER (ORDER BY date) AS prev_day_sales,  -- 前一天销量
  lead(sales, 1) OVER (ORDER BY date) AS next_day_sales   -- 后一天销量
FROM sales_data;

first_value(col) / last_value(col)

  • 功能:获取窗口内的第一个值或最后一个值。
  • 注意last_value默认在当前行截止,需显式指定窗口范围到分组末尾。
    示例
sql 复制代码
SELECT 
  user_id, 
  order_time, 
  amount,
  first_value(amount) OVER (
    PARTITION BY user_id 
    ORDER BY order_time 
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  ) AS first_order_amount,
  last_value(amount) OVER (
    PARTITION BY user_id 
    ORDER BY order_time 
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  ) AS last_order_amount
FROM orders;

三、窗口框架(Window Frame)详解

窗口框架定义了当前行的关联行范围,决定了函数的计算边界。语法:

sql 复制代码
ROWS/RANGE BETWEEN start AND end
两种框架模式:
  1. ROWS模式:按物理行号定位(不受值影响)。

    • 示例:ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING(当前行的前2行到后1行)。
  2. RANGE模式:按值的范围定位(适用于数值或时间类型)。

    • 示例:RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW(当前日期的前7天内)。
常用范围值:
  • UNBOUNDED PRECEDING:分组的第一行。
  • UNBOUNDED FOLLOWING:分组的最后一行。
  • CURRENT ROW:当前行。

四、窗口函数的典型应用场景

场景1:TopN筛选(每个分组的前N条)

需求 :找出每个部门薪资最高的前3名员工。
解法

sql 复制代码
WITH ranked_employees AS (
  SELECT 
    department, 
    name, 
    salary,
    row_number() OVER (
      PARTITION BY department 
      ORDER BY salary DESC
    ) AS rn
  FROM employees
)
SELECT * FROM ranked_employees WHERE rn <= 3;
场景2:移动统计(如7日滚动平均)

需求 :计算每日销售额的7日移动平均值。
解法

sql 复制代码
SELECT 
  date, 
  sales,
  avg(sales) OVER (
    ORDER BY date 
    ROWS BETWEEN 6 PRECEDING AND CURRENT ROW  -- 包含当前行共7天
  ) AS rolling_avg
FROM daily_sales;
场景3:环比/同比分析

需求 :计算每日销售额的环比增长率(较前一日)。
解法

sql 复制代码
SELECT 
  date, 
  sales,
  prev_day_sales,
  ((sales - prev_day_sales) / prev_day_sales) * 100 AS growth_rate
FROM (
  SELECT 
    date, 
    sales,
    lag(sales, 1) OVER (ORDER BY date) AS prev_day_sales
  FROM daily_sales
) t;
场景4:累计分布(如计算累计占比)

需求 :计算每个用户的订单金额占其总金额的累计百分比。
解法

sql 复制代码
SELECT 
  user_id, 
  order_id, 
  amount,
  sum(amount) OVER (
    PARTITION BY user_id 
    ORDER BY order_time 
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  ) / sum(amount) OVER (PARTITION BY user_id) AS cumulative_percent
FROM orders;

五、性能优化建议

  1. 合理使用窗口框架

    • 避免使用UNBOUNDED FOLLOWING,可能导致全量数据缓存。
    • 优先使用ROWS模式(比RANGE更高效)。
  2. 分区与排序优化

    • PARTITION BY的列尽量选择数据分布均匀的字段,避免数据倾斜。
    • 窗口函数的计算可能触发多次排序,可结合CTE(公共表表达式)提前排序。
  3. 大表计算避免全量窗口

    • 若数据量极大,可先通过WHERE过滤后再应用窗口函数。

六、与GROUP BY的对比

特性 窗口函数(Window Functions) GROUP BY
输出行数 保留原始行数(不压缩) 压缩为分组后的行数
聚合方式 对每个分组内的每行数据单独计算 对每个分组汇总为单行结果
典型应用 排名、移动统计、累计计算 分组求和、平均值等
能否同时访问原始列 是(可保留未参与分组的列) 否(只能访问分组列或聚合值)

总结

窗口函数是Hive处理复杂分析需求的核心工具,通过PARTITION BYORDER BY和窗口框架的组合,可实现排名分析、趋势计算、时间序列处理等高级功能。实际应用中,需根据业务场景选择合适的窗口函数类型(排名、聚合、分析),并注意窗口框架的边界定义,以确保计算结果符合预期。

相关推荐
想ai抽9 小时前
深入starrocks-多列联合统计一致性探查与策略(YY一下)
java·数据库·数据仓库
starfalling102410 小时前
【hive】一种高效增量表的实现
hive
顧棟12 小时前
【Yarn实战】Yarn 2.9.1滚动升级到3.4.1调研与实践验证
hadoop·yarn
D明明就是我15 小时前
Hive 拉链表
数据仓库·hive·hadoop
嘉禾望岗50318 小时前
hive join优化和数据倾斜处理
数据仓库·hive·hadoop
yumgpkpm19 小时前
华为鲲鹏 Aarch64 环境下多 Oracle 数据库汇聚操作指南 CMP(类 Cloudera CDP 7.3)
大数据·hive·hadoop·elasticsearch·zookeeper·big data·cloudera
忧郁火龙果20 小时前
六、Hive的基本使用
数据仓库·hive·hadoop
忧郁火龙果21 小时前
五、安装配置hive
数据仓库·hive·hadoop
chad__chang1 天前
dolphinscheduler安装过程
hive·hadoop
莫叫石榴姐2 天前
字节数开一面
大数据·数据仓库·职场和发展