我们来深入探讨一下 Hive 中这三个非常实用但又功能迥异的函数:EXPLODE()、POSEXPLODE() 和 COLLECT_SET()。它们分别代表了“行转列”和“列转行”两种经典的数据处理场景。
1. EXPLODE() - 爆炸函数(行转列)
EXPLODE() 是 Hive 中最著名的 UDTF(User-Defined Table-Generating Function)。它的核心作用是将一个复杂的 数组(Array) 或 映射(Map) 结构“炸开”,转换成多行数据,即所谓的“行转列”。
语法
SELECT EXPLODE(column_name) AS exploded_column FROM table_name;
column_name: 必须是ARRAY或MAP类型的数据类型。exploded_column: 炸开后的列别名。如果原始是数组,该列数据类型与数组元素相同;如果是 Map,则会生成key和value两列。
工作原理与示例
a) 炸开数组(ARRAY)
假设有一张表 student_courses,存储了学生和其选修的课程。
| student_id | name | courses |
|---|---|---|
| 1 | Alice | [“Math”, “Physics”] |
| 2 | Bob | [“History”] |
我们想将每个课程变成单独的一行。
SELECT student_id, name, exploded_course
FROM student_courses
LATERAL VIEW EXPLODE(courses) exploded_table AS exploded_course;
结果:
| student_id | name | exploded_course |
|---|---|---|
| 1 | Alice | Math |
| 1 | Alice | Physics |
| 2 | Bob | History |
b) 炸开映射(MAP)
假设有一张表 product_features,存储了产品及其特性的键值对。
| product_id | features |
|---|---|
| 1001 | {“color”: “red”, “size”: “10cm”} |
| 1002 | {“color”: “blue”} |
SELECT product_id, exploded_key, exploded_value
FROM product_features
LATERAL VIEW EXPLODE(features) exploded_table AS exploded_key, exploded_value;
结果:
| product_id | exploded_key | exploded_value |
|---|---|---|
| 1001 | color | red |
| 1001 | size | 10cm |
| 1002 | color | blue |
关键点:
- 必须与
LATERAL VIEW一起使用:EXPLODE()本身会生成一个虚拟表,LATERAL VIEW的作用是将这个虚拟表的结果和原始表的每一行进行关联(笛卡尔积),从而得到最终结果。 - UDTF 不能直接出现在
SELECT后与其他字段并列:例如SELECT name, EXPLODE(courses) ...是错误的语法,必须通过LATERAL VIEW。
2. POSEXPLODE() - 带位置的爆炸函数
POSEXPLODE() 是 EXPLODE() 的增强版。它在炸开数组的同时,还返回数组元素的索引(位置)。这对于需要保留元素原始顺序的场景非常有用。
语法与示例
继续使用 student_courses 表。
SELECT student_id, name, pos, course
FROM student_courses
LATERAL VIEW POSEXPLODE(courses) exploded_table AS pos, course;
结果:
| student_id | name | pos | course |
|---|---|---|---|
| 1 | Alice | 0 | Math |
| 1 | Alice | 1 | Physics |
| 2 | Bob | 0 | History |
关键点:
- 索引从 0 开始。
- 和
EXPLODE()一样,必须与LATERAL VIEW联用。 - 对于
MAP类型,POSEXPLODE()的行为与EXPLODE()一致,因为 Map 的键本身是无序的,返回位置意义不大(Hive 中 Map 的键序不确定)。
3. COLLECT_SET() - 聚合函数(列转行)
COLLECT_SET() 的作用与 EXPLODE() 完全相反。它是一个 聚合函数(UDAF),用于将分组内的多个数据收集起来,形成一个不重复(去重)的集合(Set),即数组(ARRAY)。这实现了“列转行”。
语法
SELECT grouping_column, COLLECT_SET(target_column)
FROM table_name
GROUP BY grouping_column;
target_column: 需要被聚合的列,可以是任意基本数据类型。- 返回值:
ARRAY类型,且元素唯一。
工作原理与示例
假设有一张订单明细表 orders,记录了每个用户的订单。
| user_id | order_id |
|---|---|
| A | O1 |
| A | O2 |
| A | O1 |
| B | O3 |
我们想找出每个用户拥有的所有唯一的订单 ID。
SELECT user_id, COLLECT_SET(order_id) AS unique_orders
FROM orders
GROUP BY user_id;
结果:
| user_id | unique_orders |
|---|---|
| A | [“O1”, “O2”] |
| B | [“O3”] |
变体:COLLECT_LIST()
COLLECT_LIST() 函数与 COLLECT_SET() 功能几乎完全相同,唯一的区别是:它不去重,保留所有元素,包括重复项,并且不保证元素的顺序(在 Hive 的某些版本中,顺序可能是按数据插入的物理顺序)。
使用上面的例子:
SELECT user_id, COLLECT_LIST(order_id) AS all_orders
FROM orders
GROUP BY user_id;
结果:
| user_id | all_orders |
|---|---|
| A | [“O1”, “O2”, “O1”] |
| B | [“O3”] |
关键点:
- 是一个聚合函数,必须与
GROUP BY子句一起使用。 COLLECT_SET()保证结果数组中的元素是唯一的。COLLECT_LIST()保留所有原始值,允许重复。
总结与对比
| 特性 | EXPLODE() / POSEXPLODE() | COLLECT_SET() / COLLECT_LIST() |
|---|---|---|
| 类型 | UDTF (表生成函数) | UDAF (聚合函数) |
| 功能 | 行转列:将一行中的复杂数据类型展开成多行 | 列转行:将多行的值聚合成一个数组(一行) |
| 数据量 | 输出行数 >= 输入行数(通常增加) | 输出行数 <= 输入行数(通过分组减少) |
| 关键子句 | LATERAL VIEW | GROUP BY |
| 去重 | N/A(原样展开) | COLLECT_SET() 会去重,COLLECT_LIST() 不会 |
经典组合使用场景
一个常见的 ETL 模式是先用 EXPLODE 将数据打平进行处理,最后再用 COLLECT_SET 重新聚合。
场景:统计每个用户看过的所有不同的电影标签。
原始表 user_movie_tags:
| user_id | movie_tags |
|---|---|
| 1 | [“comedy”, “action”] |
| 1 | [“action”, “sci-fi”] |
| 2 | [“drama”] |
步骤:
- 先用
EXPLODE打平,让每个标签成为一行。 - 然后按用户和标签分组(去重)。
- 最后按用户分组,用
COLLECT_SET收集所有唯一标签。
WITH exploded_data AS (
SELECT user_id, exploded_tag
FROM user_movie_tags
LATERAL VIEW EXPLODE(movie_tags) t AS exploded_tag
),
distinct_tags AS (
SELECT user_id, exploded_tag AS tag
FROM exploded_data
GROUP BY user_id, exploded_tag -- 这一步根据业务逻辑,有时可省略
)
SELECT user_id, COLLECT_SET(tag) AS all_unique_tags
FROM distinct_tags
GROUP BY user_id;
最终结果:
| user_id | all_unique_tags |
|---|---|
| 1 | [“comedy”, “action”, “sci-fi”] |
| 2 | [“drama”] |
通过这三个函数的灵活运用,可以高效地处理 Hive 中复杂的结构化数据。

2731

被折叠的 条评论
为什么被折叠?



