Spark专题-第二部分:Spark SQL 入门(6)-算子介绍-Generate
Spark专题-第二部分:Spark SQL 入门(6)-算子介绍-Generate
Generate其实是一个很危险的算子,会导致数据量急速膨胀,用的时候一定要做好评估
Generate物理算子概述
Generate
是Spark执行explode操作的物理算子,负责将输入行转换为多行输出。根据不同的explode函数,Spark会使用不同类型的生成器(Generator)。
Generate算子类型及对应实现
1. ExplodeGenerator
- 对应SQL函数:
EXPLODE
,EXPLODE_OUTER
- 物理实现: 将数组或Map的每个元素生成一行
- 执行特性: 对于空数组或null值,
EXPLODE
不生成行,EXPLODE_OUTER
生成包含null的行
2. PosExplodeGenerator
- 对应SQL函数:
POSEXPLODE
,POSEXPLODE_OUTER
- 物理实现: 将数组的每个元素及其位置索引生成一行
- 执行特性: 输出包含元素值和位置索引两列
3. InlineGenerator
- 对应SQL函数:
INLINE
,INLINE_OUTER
- 物理实现: 将结构体数组的每个元素展开为多列
- 执行特性: 每个结构体字段成为输出表的一列
物理执行计划对比
EXPLODE物理执行流程
EXPLODE_OUTER物理执行流程
实际案例与执行计划分析
案例: 用户兴趣标签展开
-- 创建包含数组的表
CREATE TABLE user_interests (user_id INT,interests ARRAY<STRUCT<category: STRING, score: DOUBLE>>
);-- 插入示例数据
INSERT INTO user_interests VALUES
(1, array(named_struct('category', 'sports', 'score', 0.8), named_struct('category', 'music', 'score', 0.6))),
(2, array(named_struct('category', 'tech', 'score', 0.9))),
(3, array());
使用EXPLODE的执行计划
EXPLAIN EXTENDED
SELECT user_id, explode(interests) AS interest
FROM user_interests;
物理执行计划:
== Physical Plan ==
*(1) Generate explode(interests#3), [user_id#0], false, [interest#8]
+- *(1) Scan ExistingRDD[user_id#0,interests#3]
使用INLINE的执行计划
EXPLAIN EXTENDED
SELECT user_id, inline(interests)
FROM user_interests;
物理执行计划:
== Physical Plan ==
*(1) Generate inline(interests#3), [user_id#0], false, [category#12, score#13]
+- *(1) Scan ExistingRDD[user_id#0,interests#3]
Generate算子的关键参数
在物理执行计划中,Generate算子包含几个重要参数:
- generator: 使用的生成器类型(explode、posexplode、inline等)
- join: 是否与外部行进行join(false表示不join)
- outer: 是否保留空值(true表示outer模式)
- output: 输出列名
性能优化考虑
1. 数据倾斜处理
2. 内存管理
Generate操作可能在单个分区内产生大量数据,需要合理设置:
-- 设置执行器内存
SET spark.executor.memory=8g;
SET spark.sql.execution.arrow.maxRecordsPerBatch=10000;
最佳实践
1. 选择合适的生成器
-- 需要位置信息时使用posexplode
SELECT user_id, pos, col
FROM table LATERAL VIEW posexplode(array_col) t AS pos, col;-- 需要展开结构体时使用inline
SELECT user_id, inline(struct_array)
FROM table_with_structs;
2. 结合其他算子优化
-- 先过滤再explode,减少数据量
SELECT user_id, explode(interests) AS interest
FROM user_interests
WHERE size(interests) > 0;
执行计划解析技巧
使用EXPLAIN CODEGEN
可以查看Generate算子的代码生成情况:
EXPLAIN CODEGEN
SELECT user_id, explode(interests) AS interest
FROM user_interests;