2、环境搭建与入门:Spark 与 Delta Lake 版本兼容性、本地开发环境配置、第一个 Delta 表读写
说实话,做大数据开发这么多年,我见过太多人在环境搭建这一步就卡住了。版本不兼容、依赖冲突、本地跑不起来……这些问题其实完全可以避免。今天我们就从零开始,把 Spark 和 Delta Lake 的环境搭好,然后亲手读写第一个 Delta 表。
核心要点:Delta Lake 是 Spark 的一个扩展库,不是独立引擎。所以版本匹配是第一步,也是最容易踩坑的一步。
2.1 Spark 与 Delta Lake 版本兼容性
Delta Lake 的版本号与 Spark 主版本是绑定的。我用一张表把主流版本的对应关系列出来,你直接对照着选就行。
| Delta Lake 版本 | 兼容的 Spark 版本 | 备注 |
|---|---|---|
| 0.6.x - 0.7.x | Spark 2.4.x | 早期版本,已不推荐使用 |
| 1.0.x - 1.2.x | Spark 3.0.x | API 变化较大,注意迁移 |
| 2.0.x - 2.4.x | Spark 3.2.x - 3.4.x | 当前主流,功能稳定 |
| 3.0.x | Spark 3.5.x | 最新版本,支持 Liquid Clustering |
我个人习惯是选 Delta Lake 2.x + Spark 3.3.x 这个组合。为什么?因为我在生产环境跑了大半年,没出过什么幺蛾子。社区支持也最活跃,遇到问题搜一下基本都有答案。
注意:千万不要把 Delta Lake 2.x 和 Spark 3.0.x 混用。我见过有人图省事直接 pip install delta-spark,结果运行时抛了一堆 NoSuchMethodError。版本不匹配,底层 API 对不上,跑起来全是坑。
2.2 本地开发环境配置
本地环境我推荐用 PySpark + Jupyter Notebook 来搭。调试方便,反馈快。你想想看,每次改代码都要打包提交到集群,那效率得多低。
2.2.1 安装 Java 和 Python
Spark 跑在 JVM 上,所以 Java 是必须的。Python 3.8 以上就行。
# 检查 Java 版本
java -version
# 输出示例:openjdk version "11.0.18" 2023-01-17 LTS
# 检查 Python 版本
python --version
# 输出示例:Python 3.9.16
2.2.2 安装 PySpark 和 Delta Lake
这里有个小技巧:直接用 pip 安装 delta-spark 包,它会自动拉取对应版本的 PySpark。
# 创建虚拟环境(推荐)
python -m venv delta_env
source delta_env/bin/activate # Linux/Mac
# delta_env\Scripts\activate # Windows
# 安装 delta-spark
pip install delta-spark==2.4.0
# 验证安装
python -c "import delta; print(delta.__version__)"
嗯,这里要注意:如果你在公司内网,可能需要配置代理或者使用离线包。我曾经在客户现场折腾了一下午,就是因为网络不通,pip 一直超时。
2.2.3 启动 PySpark 并集成 Delta Lake
启动时需要指定 Delta Lake 的包。有两种方式:
# 方式一:命令行指定
pyspark --packages io.delta:delta-core_2.12:2.4.0
# 方式二:代码中配置(推荐,更灵活)
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("DeltaLakeDemo") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
.getOrCreate()
print("Spark 版本:", spark.version)
小提示:方式二的好处是配置都在代码里,换环境时不用改启动脚本。我一般把这段配置封装成一个工具函数,项目里直接调用就行。
2.3 第一个 Delta 表读写
环境搭好了,我们来写第一个 Delta 表。说白了,Delta 表就是一个带事务日志的 Parquet 文件夹。读写操作和普通 Spark DataFrame 几乎一样,只是多了几个选项。
2.3.1 创建 Delta 表
# 准备一些示例数据
data = [("Alice", 34), ("Bob", 45), ("Cathy", 29)]
columns = ["name", "age"]
df = spark.createDataFrame(data, columns)
# 保存为 Delta 表
df.write.format("delta").save("/tmp/delta_table")
print("Delta 表创建成功!")
就这么简单?对,就这么简单。你打开 /tmp/delta_table 目录看看,会发现除了 Parquet 数据文件,还有一个 _delta_log 文件夹。这就是 Delta Lake 的核心——事务日志。
2.3.2 读取 Delta 表
# 读取 Delta 表
df_read = spark.read.format("delta").load("/tmp/delta_table")
df_read.show()
# 输出:
# +-----+---+
# | name|age|
# +-----+---+
# |Alice| 34|
# | Bob| 45|
# |Cathy| 29|
# +-----+---+
2.3.3 更新和删除数据
Delta Lake 支持 ACID 事务,所以你可以像操作数据库一样更新和删除数据。
from delta.tables import DeltaTable
# 加载 Delta 表
delta_table = DeltaTable.forPath(spark, "/tmp/delta_table")
# 更新:将 Bob 的年龄改为 46
delta_table.update(
condition="name = 'Bob'",
set={"age": "46"}
)
# 删除:删除 Cathy 的记录
delta_table.delete(condition="name = 'Cathy'")
# 查看结果
spark.read.format("delta").load("/tmp/delta_table").show()
# 输出:
# +-----+---+
# | name|age|
# +-----+---+
# |Alice| 34|
# | Bob| 46|
# +-----+---+
注意:update 和 delete 操作不会真的修改原文件。Delta Lake 会写入新文件,并在事务日志中标记旧文件为已删除。所以数据量大的时候,记得定期执行 VACUUM 清理旧版本文件。
2.4 知识体系总览
下面这张图把本章的核心知识点串起来了。你可以对照着检查自己是否都掌握了。
2.5 常见问题与避坑指南
- 问题:启动时提示 ClassNotFoundException: io.delta.sql.DeltaSparkSessionExtension
- 原因:Delta Lake 的 JAR 包没有加载到 classpath 中
- 解决:检查 --packages 参数是否正确,或者确认 pip 安装的版本与 Spark 版本匹配
- 问题:写入 Delta 表时提示 Path already exists
- 原因:目标路径已存在,默认不允许覆盖
- 解决:使用 .mode("overwrite") 或先删除目录
- 问题:读取 Delta 表时数据为空
- 原因:可能是路径不对,或者事务日志损坏
- 解决:检查 _delta_log 目录是否存在,以及日志文件是否完整
我的经验:刚开始学 Delta Lake 时,我习惯在本地用小型数据集反复测试。比如创建表、更新、删除、时间旅行查询,每个操作都验证一下事务日志的变化。这样理解起来特别快,比光看文档强多了。
好了,环境搭好了,第一个 Delta 表也读写成功了。接下来你就可以放心地在这个基础上做更复杂的操作了。记住,Delta Lake 的核心优势在于事务日志,后面我们会深入探讨它如何实现 ACID、时间旅行和 Schema 演化。