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 知识体系总览

下面这张图把本章的核心知识点串起来了。你可以对照着检查自己是否都掌握了。

环境搭建与入门 · 知识体系 版本兼容性 环境配置 第一个 Delta 表 Delta 2.x + Spark 3.3 版本对照表 Java + Python pip install delta-spark 创建 / 读取 更新 / 删除 核心概念:事务日志 (_delta_log) SparkSession DataFrame DeltaTable ACID 操作 Delta Lake = Parquet 数据文件 + 事务日志 (_delta_log)

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 演化。