DataFrame/Dataset API 详解(以 Spark 3.x 为例)
DataFrame 和 Dataset 是 Spark 结构化数据处理的核心抽象,基于 Spark SQL 引擎构建,提供高性能、类型安全的操作。二者共享大部分 API(DataFrame = Dataset[Row]
)。
一、核心概念
-
DataFrame
- 分布式数据集合,按命名列组织(类似关系型数据库表)
- 弱类型(运行时类型检查)
- 优化器自动优化执行计划
-
Dataset (Scala/Java)
- 强类型 API(编译时类型安全)
- 需定义 case class 或 JavaBean
case class Person(name: String, age: Int)
val ds: Dataset[Person] = spark.read.json("path").as[Person]
二、创建 DataFrame/Dataset
数据源 | 示例代码 |
---|
JSON 文件 | spark.read.json("data.json") |
CSV 文件 | spark.read.option("header",true).csv("data.csv") |
Parquet 文件 | spark.read.parquet("data.parquet") |
RDD 转换 | rdd.toDF("col1","col2") |
Hive 表 | spark.sql("SELECT * FROM hive_table") |
三、核心操作分类
1. 转换操作(Transformations)
(1) 列操作
API | 说明 | 示例 |
---|
select() | 选择列 | df.select($"name", $"age" + 1) |
withColumn() | 添加/替换列 | df.withColumn("age2", $"age" * 2) |
drop() | 删除列 | df.drop("temp_col") |
cast() | 类型转换 | df.withColumn("age", $"age".cast("int")) |
(2) 过滤
API | 示例 |
---|
filter() | df.filter($"age" > 30) |
where() | df.where($"salary" < 5000) |
(3) 聚合
API | 说明 | 示例 |
---|
groupBy() | 分组 | df.groupBy("department") |
agg() | 聚合函数 | grouped.agg(avg($"salary"), max($"age")) |
rollup() | 多维聚合 | df.rollup("city", "year").sum("revenue") |
(4) 连接
类型 | API |
---|
内连接 | df1.join(df2, $"id1" === $"id2") |
左外连接 | df1.join(df2, Seq("id"), "left_outer") |
交叉连接 | df1.crossJoin(df2) |
(5) 窗口函数
import org.apache.spark.sql.expressions.Window
val window = Window.partitionBy("dept").orderBy($"salary".desc)
df.withColumn("rank", rank().over(window))
2. 行动操作(Actions)
API | 说明 |
---|
show() | 打印前 n 行(默认 20) |
count() | 返回行数 |
collect() | 返回所有数据到 Driver(慎用) |
write.save() | 写入数据源 |
四、高级特性
1. UDF(用户自定义函数)
from pyspark.sql.functions import udf
from pyspark.sql.types import IntegerType
add_one = udf(lambda x: x + 1, IntegerType())
df.select(add_one($"age"))
2. Catalyst 优化器
- 逻辑优化:谓词下推、常量折叠等
- 物理优化:选择最优 Join 策略
3. Tungsten 执行引擎
- 堆外内存管理
- 代码生成(Code Generation)
五、执行计划查看
df.explain()
df.explain(extended = true)
六、数据写入
df.write
.format("parquet")
.mode("overwrite")
.option("path", "output/")
.save()
七、性能优化技巧
- 分区剪枝(Partition Pruning)
spark.read.parquet("/data/year=2023/month=08")
- 谓词下推(Predicate Pushdown)
自动将过滤条件下推到数据源层 - 缓存常用数据
df.cache()
八、对比 RDD API
特性 | DataFrame/Dataset | RDD |
---|
优化 | Catalyst 自动优化 | 手动优化 |
序列化 | Tungsten 二进制 | Java 序列化 |
API | 声明式 | 过程式 |
类型 | 结构化/半结构化 | 任意数据 |
最佳实践:优先使用 DataFrame API,需要类型安全时用 Dataset,避免混合 RDD 操作以确保优化器生效。
通过这套 API,Spark 在保持易用性的同时,实现了接近手写代码的性能,特别适合大规模数据批处理和流处理场景。