函数
Hive 函数:内置函数够用 80% 的场景,窗口函数是分析利器,UDF 是最后一张牌
Hive 的函数分三类:
| 类型 | 输入 → 输出 | 典型函数 |
|---|---|---|
| UDF | 一行 → 一行 | concat、nvl、date_format |
| UDAF | 多行 → 一行 | sum、avg、collect_set |
| UDTF | 一行 → 多行 | explode、split |
日常开发中,80% 的需求用内置 UDF 和 UDAF 就能解决。窗口函数是进阶工具,解决”既要聚合又要保留明细”的问题。 自定义 UDF 是最后的手段——内置函数实在搞不定了再写
函数查询与帮助
查看所有内置函数:
hive> show functions; -- 列出所有可用函数查看函数用法:
-- 基础说明 hive> desc function concat; -- 详细说明(含示例) hive> desc function extended concat;模糊查询函数:
hive> desc function like '*date*'; -- 查找含“date”的函数
数据清洗类函数
空值处理:nvl
-- 薪资为空时补 0
SELECT ename, nvl(sal, 0) FROM emp;
字符串拼接:concat / concat_ws
-- concat:直接拼,有一个 NULL 整个结果是 NULL
SELECT concat(ename, '_', deptno) FROM emp;
-- concat_ws:指定分隔符,自动跳过 NULL
SELECT concat_ws(',', ename, deptno, sal) FROM emp;
字符串切割:split
-- 把逗号分隔的标签切成数组
SELECT split('java,python,sql', ',') FROM dual;
-- 输出:["java","python","sql"]
数组展开:explode + lateral view
explode 把数组拆成多行,但必须跟 lateral view 配合使用:
-- 把每个标签拆成一行,同时保留订单 ID
SELECT order_id, tag
FROM orders
LATERAL VIEW explode(split(tags, ',')) t AS tag;
日期处理函数
| 函数 | 作用 | 示例 |
|---|---|---|
date_format |
日期格式化 | date_format('2026-07-01', 'yyyyMMdd') → 20260701 |
unix_timestamp |
日期 → 时间戳 | unix_timestamp('2026-07-01', 'yyyy-MM-dd') |
from_unixtime |
时间戳 → 日期 | from_unixtime(1696108800, 'yyyy-MM-dd') |
跨格式转换:先转时间戳,再转目标格式
-- 把 '2026/07/01' 转成 '20260701'
SELECT from_unixtime(
unix_timestamp('2026/07/01', 'yyyy/MM/dd'),
'yyyyMMdd'
);
聚合函数:多行 → 一行
| 函数 | 作用 |
|---|---|
sum |
求和 |
avg |
平均值 |
count |
计数 |
max / min |
最大 / 最小值 |
collect_set |
去重合并成数组 |
collect_list |
不去重合并成数组 |
-- 按部门汇总
SELECT deptno,
sum(sal) AS total_sal,
avg(sal) AS avg_sal,
collect_set(ename) AS employees
FROM emp
GROUP BY deptno;
窗口函数:聚合 + 保留明细
窗口函数是 Hive 最强大的分析工具。它的核心价值是:在保留每一行原始数据的同时,做聚合计算。
普通聚合 vs 窗口函数:
-- 普通聚合:结果只显示一行(部门汇总)
SELECT deptno, sum(sal) FROM emp GROUP BY deptno;
-- 输出:10 11000
-- 窗口函数:每一行都保留,同时显示部门汇总
SELECT ename, deptno, sal,
sum(sal) OVER(PARTITION BY deptno) AS dept_total
FROM emp;
-- 输出:
-- 张三 10 5000 11000
-- 李四 10 6000 11000
-- 王五 20 3000 3000
窗口函数的基本结构:
函数() OVER (
PARTITION BY 分组列 -- 可选,不写就是全表
ORDER BY 排序列 -- 可选
ROWS BETWEEN ... -- 可选,定义窗口范围
)
常用窗口函数:
| 函数 | 作用 |
|---|---|
sum() OVER() |
累计求和 |
avg() OVER() |
移动平均 |
rank() OVER() |
排名(有间隔) |
dense_rank() OVER() |
排名(无间隔) |
row_number() OVER() |
行号 |
lag(列, n) |
取前 n 行的值 |
lead(列, n) |
取后 n 行的值 |
场景1:按部门排名
SELECT ename, deptno, sal,
rank() OVER(PARTITION BY deptno ORDER BY sal DESC) AS rnk
FROM emp;
rank vs dense_rank vs row_number:
| 函数 | 相同值行为 |
|---|---|
rank() |
1, 2, 2, 4(跳过) |
dense_rank() |
1, 2, 2, 3(连续) |
row_number() |
1, 2, 3, 4(不重复) |
场景2:累计求和
-- 按薪资升序,计算累计总和
SELECT ename, sal,
sum(sal) OVER(ORDER BY sal
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cum_sal
FROM emp;
场景3:同比/环比(取上一条数据)
-- 取上一个月的销售额
SELECT month, sales,
lag(sales, 1) OVER(ORDER BY month) AS prev_month_sales
FROM sales_table;
自定义函数 UDF:内置不够用的时候再写
三步走:
1. 写 Java 类,继承 UDF,重写 evaluate
import org.apache.hadoop.hive.ql.exec.UDF;
public class UpperCaseUDF extends UDF {
public String evaluate(String input) {
if (input == null) return null;
return input.toUpperCase();
}
}
2. 打包成 JAR,上传
上传到 HDFS
hdfs dfs -put hive-udf.jar /user/hive/udf/
3. 在 Hive 里注册
-- 临时函数(当前会话有效)
ADD JAR /path/to/hive-udf.jar;
CREATE TEMPORARY FUNCTION upper_udf AS 'com.example.UpperCaseUDF';
-- 永久函数(全局有效)
CREATE FUNCTION upper_udf AS 'com.example.UpperCaseUDF'
USING JAR 'hdfs:///user/hive/udf/hive-udf.jar';
4. 使用
SELECT upper_udf('hello') FROM dual; -- HELLO