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 常用函数与典型分析场景。

相关推荐
爱吃火鸡面呀1 小时前
DataX 实战:使用 HDFS Reader 读取 Hive ORC 表并输出到 Stream
hive·hadoop·hdfs
yi0112 小时前
LeetCode 643. 子数组最大平均数 I|从暴力枚举到滑动窗口
人工智能·笔记·python·算法·leetcode·滑动窗口
罗西的思考2 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 — (6)— 奖励机制
人工智能·笔记·学习
yumgpkpm2 小时前
CDP 7.3.1(Cloudera Runtime 7.3.1)VS Acceldata ODP 3.3.6.4 核心引擎详细版本对比
大数据·hive·hadoop·postgresql·zookeeper·spark·hbase
拾饵9423 小时前
第六周第二个项目笔记:FinInsRAG 项目学习笔记(零基础版)以及简历书写
笔记·学习
han68893 小时前
selenium之实战
笔记·python·selenium·测试工具·自动化
Lost_the_wind3 小时前
MySQL 学习笔记三
笔记·学习·mysql
欣欣之王来了3 小时前
开发环境准备:Node.js、npm、VS Code安装配置
前端·学习·架构·项目·vue3教程
火眼金睛记单词4 小时前
阅读理解核心词汇:破解英语阅读难题的利器
经验分享·学习