当前位置: 首页 > news >正文

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物理执行流程

Generate算子内部处理
输入行: 1, 'Alice', 'tech', 'sports', 'music'
ExplodeGenerator处理
输出行- 1, 'Alice', 'tech'
输出行-1, 'Alice', 'sports'
输出行- 1, 'Alice', 'music'
TableScan user_tags
Project: user_id, user_name, tags
Generate: ExplodeGenerator
Filter: 可选的条件过滤
Output

EXPLODE_OUTER物理执行流程

Generate算子内部处理
输入行: 3, Charlie,
ExplodeGenerator outer=true处理
输出行: 3, Charlie, null
输入行: 4, David, null
ExplodeGenerator outer=true处理
输出行: 4, David, null
TableScan user_tags
Project: user_id, user_name, tags
Generate: ExplodeGenerator outer=true
Output

实际案例与执行计划分析

案例: 用户兴趣标签展开

-- 创建包含数组的表
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]
Generate算子细节
输入分区数据
ExplodeGenerator: 遍历每个数组元素
为每个元素生成输出行
outer=false: 跳过空数组
Scan ExistingRDD
Generate explodeinterests
Output

使用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]
InlineGenerator处理
输入行: 1, structsports,0.8, structmusic,0.6
展开结构体数组
输出行: 1, sports, 0.8
输出行: 1, music, 0.6
Scan ExistingRDD
Generate inlineinterests
Output

Generate算子的关键参数

在物理执行计划中,Generate算子包含几个重要参数:

  1. generator: 使用的生成器类型(explode、posexplode、inline等)
  2. join: 是否与外部行进行join(false表示不join)
  3. outer: 是否保留空值(true表示outer模式)
  4. 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;
http://www.dtcms.com/a/394138.html

相关文章:

  • C#练习题——Dictionary
  • Feign
  • SPA小说集之三《森林城市反甩锅战:ERP的权责边界》
  • Qt(模态对话框和非模态对话框)
  • 【无标题】物联网 frid卡控制
  • 【LLM LangChain】 模型绑定工具+调用工具(手动调用/LangGraph/AgentExecutor)+相关注意事项
  • 图神经网络(GNN)入门:用PyG库处理分子结构与社会网络
  • 【C++】编码表 STL简介:STL是什么,版本,六大组件,重要性以及学习方法总结
  • show_interrupts函数的进一步解析及irq_desc结构体
  • Kafka面试精讲 Day 19:JVM调优与内存管理
  • 10.vector容器
  • Linux系统介绍
  • MFC中的CMFCDynamicLayout类的介绍
  • UniScene 统一驾驶场景 | 生成语义占据 | 生成多视角视频 | 生成激光点云 CVPR2025
  • Git 简明教程:从原理到实战
  • 【设计模式】中介者模式
  • nginx添加modsecurity插件
  • 代码上传Github:SSH法
  • 【iOS】AFNetworking初步了解及使用
  • JVM实战-G1参数调优
  • 超简单的视频分割脚本
  • 基于51单片机电子钟闹钟12/24小时制LCD显示( proteus仿真+程序+设计报告+讲解视频)
  • 在 Windows 系统上安装官方 Codex CLI 教程
  • Redis 配置与优化全攻略
  • 二分查找左右边界写法
  • Oracle体系结构-Large Pool详解
  • Elasticsearch面试精讲 Day 19:磁盘IO与存储优化
  • 【AI智能体】Dify 搭建数据分析应用实战操作详解
  • Nginx localtion / 、/a、/a/ 的区别
  • 【C++】string的使用与模拟实现