Hive 函数学习笔记(下):窗口函数与经典案例

本文继续整理 Hive 函数的下半部分内容,涵盖窗口函数、行列转换、连续登录等经典问题。 上半部分已整理单行函数与炸裂函数,可配合阅读。


一、Hive 窗口函数

1. 数据准备

创建学生表:

复制代码
CREATE TABLE students(
    id STRING,
    name STRING,
    age STRING,
    gender STRING,
    clazz STRING
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
    OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION '/data/students';

创建成绩表:

复制代码
CREATE TABLE scores(
    id STRING,
    cid STRING,
    score DOUBLE
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
    OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION '/data/scores';

2. 窗口函数案例

计算每个科目分数占总分的比例

缺点: 产生两个 MapReduce,效率比较低。

复制代码
SELECT
    a.id,
    a.cid,
    a.score,
    b.sum_score,
    round(a.score / b.sum_score,2) AS p
FROM
    bigdata.scores AS a
JOIN(
    SELECT
        id,
        sum(score) AS sum_score
    FROM
        bigdata.scores
    GROUP BY
        id
) AS b
ON a.id = b.id;

使用 sum() over():

复制代码
SELECT
    id,
    cid,
    score,
    sum_score,
    round(score / sum_score,2) AS p
FROM
(
    SELECT
        id,
        cid,
        score,
        sum(score) over(partition BY id) AS sum_score
    FROM
        bigdata.scores
) AS a;

使用 max() over():

复制代码
SELECT
    id,
    cid,
    score,
    max(score) over(partition BY id) AS max_score
FROM
    bigdata.scores;

使用 count() over():

复制代码
SELECT
    id,
    cid,
    score,
    count(1) over(partition BY id) AS max_score
FROM
    bigdata.scores;

3. 窗口内排序

累积求和:

复制代码
SELECT
    id,
    cid,
    score,
    sum(score) over(partition BY id ORDER BY cid ASC) AS sum_score
FROM scores;

逐个比较求最大值:

复制代码
SELECT
    id,
    cid,
    score,
    max(score) over(partition BY id ORDER BY cid) AS max_score
FROM scores;

逐个求平均值:

复制代码
SELECT
    id,
    cid,
    score,
    avg(score) over(partition BY id ORDER BY cid) AS num
FROM scores;

4. 排序类窗口函数

1. row_number

组内排序:

复制代码
SELECT
    id,
    cid,
    score,
    row_number() over(partition BY id ORDER BY score DESC) AS rn
FROM scores;

全局排序 ------ 求 TopN 问题:

复制代码
SELECT
    id,
    sum(score) AS sum_score,
    row_number() over(ORDER BY sum(score) DESC) AS rn   -- 不能使用别名
FROM scores
GROUP BY id;
2. rank
复制代码
SELECT
    id,
    sum(score) AS sum_score,
    rank() over(ORDER BY sum(score) DESC) AS rk
FROM scores
GROUP BY id;
3. dense_rank
复制代码
SELECT
    id,
    sum(score) AS sum_score,
    dense_rank() over(ORDER BY sum(score) DESC) AS dr
FROM scores
GROUP BY id;

5. 取值类窗口函数

lag:取前面的数据,没有则补 0

复制代码
SELECT
    id,
    sum(score) AS sum_score,
    lag(sum(score),1,0) over(ORDER BY sum(score) DESC) AS last_score
FROM scores
GROUP BY id;

lead:取后面的数据

复制代码
SELECT
    id,
    sum(score) AS sum_score,
    lead(sum(score),1,0) over(ORDER BY sum(score) DESC) AS lead_score
FROM scores
GROUP BY id;

first_value:取窗口内某一列的第一个值

复制代码
SELECT
    id,
    score,
    first_value(score) over(partition BY id ORDER BY score DESC) AS fv_score
FROM scores;

last_value:取窗口内某一列的最后一个值

复制代码
SELECT
    id,
    score,
    last_value(score) over(partition BY id ORDER BY score DESC) AS lv_score
FROM scores;

二、经典问题一:行列转换

行列转换是 Hive 中非常常见的需求,主要分两大类:

  • 行转列:多行 → 一列(聚合/拼接)
  • 列转行 :一列/多列 → 多行(炸开/展开) Hive 中行列转换的基本原理是通过特定的内置函数实现,将一列数据展开成多行(列转行)或将多行数据聚合到一列(行转列)。

表1

复制代码
姓名,科目,分数
name,item,score
张三,数学,33
张三,英语,77
李四,数学,66
李四,英语,78

CREATE TABLE table1(
    name STRING,
    item STRING,
    score DOUBLE
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
LOAD DATA LOCAL INPATH '/root/sh_code/table1.csv' OVERWRITE INTO TABLE bigdata.table1;

表2

复制代码
姓名,数学,英语
name,math,english
张三,33,77
李四,66,78

需求:将表1转换为表2(多行转多列:行转列)

使用 CASE WHEN + MAX / SUM。

复制代码
CREATE TABLE table2 AS
SELECT
    name,
    -- 汇总数学成绩:如果 item 等于 数学,取 score 成绩,否则取 0,再按学生求和
    sum(
        CASE
           WHEN item = '数学' THEN score
           ELSE 0
        END
    ) AS math,
    -- 汇总英语成绩:如果 item 等于 英语,取 score 成绩,否则取 0,再按学生求和
    sum(
        CASE
           WHEN item = '英语' THEN score
           ELSE 0
        END
    ) AS english
FROM table1
GROUP BY name;

需求:将表2转换为表1(列转行)

复制代码
SELECT
    name,
    item,
    score
FROM
    table2,
-- 使用 lateral view explode,将每个学生的数学和英语转换成多行记录
LATERAL VIEW explode(
    map(
        '数学',math,  -- map 的 key 为数学,value 33.0,66.0
        '英语',english -- map 的 key 为英语,value 77.0,78.0
    )
) T AS item,score;

三、经典问题二:连续登录

数据

复制代码
user_id,login_date
01,2021-02-28
01,2021-03-01
01,2021-03-02
01,2021-03-04
01,2021-03-05
01,2021-03-06
01,2021-03-08
02,2021-03-01
02,2021-03-02
02,2021-03-03
02,2021-03-04
02,2021-03-06
03,2021-03-06

CREATE TABLE user_login_log(
    user_id STRING,
    login_date STRING
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
LOAD DATA LOCAL INPATH '/root/sh_code/user_login_log.csv' OVERWRITE INTO TABLE bigdata.user_login_log;

需求:连续登录天数超过三天的用户

解法:利用日期与序号的差值分组(窗口函数 row_number)

复制代码
SELECT
    user_id,  -- 用户 id
    -- 连续登录开始时间
    min(login_date) AS min_login_date,
    -- 连续登录结束时间
    max(login_date) AS max_login_date,
    -- 用 login_date 与 row_number 的差值作为分组依据(相同的差值表示连续)
    date_sub(login_date,rank) AS sub_date,
    -- 求连续登录统计
    count(1) AS num
FROM(
    SELECT
        user_id,
        login_date,
        -- 每个用户的登录记录按日期进行排序,并生成序号
        row_number() over(partition BY user_id ORDER BY login_date) AS rank
    FROM
        user_login_log
) AS a
GROUP BY user_id,date_sub(login_date,rank)
HAVING num >= 3;

解法2:窗口函数 + 分组标记

注:原文件在此处结束,未给出解法2的具体代码。


四、总结(下)

本文整理了 Hive 函数的下半部分内容,包括:

  • 窗口函数的基本用法与案例;
  • 计算科目分数占比的两种方式;
  • 窗口内排序、累积求和、逐个比较求最大值/平均值;
  • 排序类窗口函数:row_number、rank、dense_rank;
  • 取值类窗口函数:lag、lead、first_value、last_value;
  • 经典问题一:行列转换(行转列、列转行);
  • 经典问题二:连续登录(利用日期与序号差值分组)。

结合上半部分的单行函数与炸裂函数,可以较完整地掌握 Hive 常用函数与典型分析场景。

相关推荐
一木 之林11 小时前
Dify学习笔记 03 · RAG检索增强生成:三代范式、评估与落地(第40-45、55-56集)
笔记·小程序·交互·dify
apple-mapping11 小时前
网络RTK定位学习总结
学习·网络rtk
楚山之石12 小时前
【Lancet Neurology 】多发性硬化认知障碍的 SDMT 筛查、灰质萎缩标志与认知康复循证路径
图像处理·人工智能·学习·mri
海海不掉头发14 小时前
CSDN博客_时序预测9模型复现对比
人工智能·学习·软件工程
蓝祁子yoky16 小时前
Qt学习日记 Day13:网络编程(一)-TCP基础与Socket实战
网络·qt·学习
箓维16 小时前
TCP Socket的进阶实现
网络·笔记·tcp/ip
二哈赛车手16 小时前
新人笔记---hermes定时功能设计,具体讲解以及可优化点
java·人工智能·笔记·spring·ai·typescript
架构师伯子明17 小时前
Ros 学习十三:IK Demo
学习
小羊没烦恼!17 小时前
关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
java·服务器·网络·学习·负载均衡
幼儿园蛋小黄17 小时前
从 STM32N647 的 AI 部署入门嵌入式:一条可落地的学习路线
人工智能·stm32·学习