3. 数据湖与Delta Lake集成基础
在 Databricks 机器学习平台上,数据湖是承载原始数据、特征数据与训练样本的底层存储基础。传统数据湖通常基于对象存储(如 S3、ADLS、GCS)保存 Parquet、ORC、JSON 等文件,具备容量大、成本低、格式开放的优势,但缺少事务、并发控制和一致性保障。Delta Lake 在数据湖之上引入事务日志与表协议,使数据湖具备 ACID 能力,从而成为机器学习特征工程、样本管理和模型训练数据准备的可靠底座。
数据湖与 Delta Lake 的关系
数据湖解决“数据放在哪里”的问题,Delta Lake 解决“数据如何被可靠地读写和演进”的问题。Delta 表在物理上仍然是对象存储中的一组 Parquet 数据文件,外加一个 _delta_log 目录。所有对表的修改不会直接覆盖原文件,而是以追加方式写入新的日志条目,记录本次事务新增、删除或修改了哪些文件。读取时,Delta 通过回放事务日志确定当前有效的数据文件集合,因此同一份底层文件可以支持快照读、时间旅行和并发写入。
ACID 特性在 Delta 表上的体现
原子性(Atomicity)意味着一次写入要么全部生效,要么完全不生效。Delta 通过“先写数据文件,再提交日志”的顺序保证:如果日志提交失败,新增的 Parquet 文件不会被任何快照引用,读取方看不到半成品数据。一致性(Consistency)由表协议和 schema 约束保证,写入必须符合当前表结构。隔离性(Isolation)依赖乐观并发控制:多个写入者可以同时尝试提交,提交时检查是否与已提交版本冲突,冲突则重试或失败。持久性(Durability)由对象存储的多副本机制承担,日志一旦提交即持久保存。
在机器学习场景中,ACID 的价值非常直接。例如特征回填任务与在线推理特征写入可能同时发生,如果没有隔离性,读取方可能看到部分回填的数据,导致训练样本与线上特征分布不一致。Delta 的可串行化隔离让读取方始终看到某个完整版本,从而保证特征一致性。
表创建与读写
在 Databricks 中创建 Delta 表通常使用 SQL 或 PySpark。以下示例创建一个用户画像特征表,并写入两条示例数据:
CREATE TABLE IF NOT EXISTS ml_features.user_profile (
user_id BIGINT,
age INT,
city STRING,
is_premium BOOLEAN,
updated_at TIMESTAMP
)
USING DELTA
LOCATION '/mnt/lake/features/user_profile';
INSERT INTO ml_features.user_profile VALUES
(1001, 28, 'Shanghai', true, '2024-06-01 10:00:00'),
(1002, 35, 'Beijing', false, '2024-06-01 10:05:00');
读取时可以直接查询表名,也可以读取路径。Delta 会自动合并小文件并利用统计信息做数据跳过。对于机器学习训练,常用写法是读取最新快照并筛选时间窗口:
SELECT user_id, age, city, is_premium
FROM ml_features.user_profile
WHERE updated_at >= '2024-06-01';
写入方面,INSERT 适合追加,MERGE INTO 适合按主键做 upsert。例如将每日增量用户画像合并进主表:
MERGE INTO ml_features.user_profile AS t
USING ml_features.user_profile_daily AS s
ON t.user_id = s.user_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
执行后可通过 DESCRIBE HISTORY ml_features.user_profile 查看版本、操作类型、时间戳和操作指标,确认写入是否成功以及影响行数。
模式演化
机器学习特征经常新增字段,例如新增 lifecycle_stage 或 embedding_version。Delta 支持安全的模式演化。默认情况下,写入时如果出现新列会报错,需要显式开启:
ALTER TABLE ml_features.user_profile
ADD COLUMN lifecycle_stage STRING;
-- 或在写入时自动合并 schema
SET spark.databricks.delta.schema.autoMerge.enabled = true;
模式演化分为两类:追加新列是向后兼容的,旧数据该列为 null;删除列或修改列类型属于破坏性变更,需要重建表或使用 overwriteSchema。在特征平台中,建议只做追加式演化,并在特征注册表中记录 schema 版本,避免训练与推理特征错位。
时间旅行查询
时间旅行让读取方可以按版本号或时间戳查询历史快照,这对复现训练数据集、排查特征异常非常关键。语法如下:
-- 按版本号
SELECT * FROM ml_features.user_profile VERSION AS OF 2;
-- 按时间戳
SELECT * FROM ml_features.user_profile
TIMESTAMP AS OF '2024-06-01 10:00:00';
-- 查看历史
DESCRIBE HISTORY ml_features.user_profile;
假设某次训练使用了版本 5 的特征,但线上效果下降,可以分别读取版本 5 和版本 6 做对比,定位是哪个字段或哪批数据发生了变化。需要注意,时间旅行依赖日志和数据文件同时存在;如果执行了 VACUUM 删除旧文件,超过保留期的历史版本将无法读取。默认保留期为 7 天,生产环境应根据合规和复现需求调整。
updated_at 和 data_version 字段,训练样本生成时记录所用 Delta 版本号,便于后续审计与复现。VACUUM 或 DELETE 完成。综合来看,Delta Lake 让数据湖从“能存”升级为“能可靠读写、能演进、能追溯”。在 Databricks 机器学习平台中,特征表、训练样本表和推理日志表都建议使用 Delta 格式,以 ACID、模式演化和时间旅行支撑从特征工程到模型上线的完整链路。