3. 数据层架构设计
在 Databricks 机器学习平台中,数据层不是简单的“存表”问题,而是决定特征可复用性、训练可复现性与线上推理一致性的基础。一个生产级数据层通常由三层能力叠加而成:Delta Lake 负责存储格式与事务语义,Unity Catalog 负责跨工作区的统一元数据、权限与血缘,特征表(Feature Store) 负责把离线特征与在线特征组织成可被训练和推理共同消费的资产。三者不是并列关系,而是“存储底座—治理平面—特征接口”的纵向分工。
Delta Lake:把数据湖变成可事务的表
Delta Lake 的核心价值在于用 _delta_log 事务日志为 Parquet 数据文件加上 ACID 能力。每次写入都会生成一个新的 JSON 提交,记录新增/删除的文件、schema 变化和统计信息。读取时先解析日志得到某个版本的文件清单,再扫描对应 Parquet 文件,因此可以做到快照隔离、时间旅行和并发写入冲突检测。
对特征工程而言,最常用的三个能力是:
- MERGE 增量更新:按主键把新批次特征合并进特征表,避免全量重写。
- 时间旅行:用
VERSION AS OF或TIMESTAMP AS OF复现某次训练所用的特征快照。 - OPTIMIZE / Z-ORDER:合并小文件并按查询高频列聚簇,降低点查与范围扫描成本。
一个典型的特征表建表与增量写入可以写成:
CREATE TABLE IF NOT EXISTS ml_prod.features.user_behavior (
user_id BIGINT,
feature_ts TIMESTAMP,
click_cnt_7d INT,
order_amt_30d DECIMAL(18,2),
last_login_gap DOUBLE
)
USING DELTA
PARTITIONED BY (DATE(feature_ts))
TBLPROPERTIES (
'delta.autoOptimize.optimizeWrite' = 'true',
'delta.autoOptimize.autoCompact' = 'true'
);
MERGE INTO ml_prod.features.user_behavior AS t
USING ml_stage.features.user_behavior_inc AS s
ON t.user_id = s.user_id AND t.feature_ts = s.feature_ts
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
这里 feature_ts 是特征的计算时间,而不是写入时间,它决定了后续 point-in-time 关联的正确性。分区键选择 DATE(feature_ts) 是为了让按天回溯和按天清理都变成分区裁剪操作。
Unity Catalog:三层命名空间与统一治理
Unity Catalog 把对象组织为 catalog.schema.table 三层命名空间,并在此之上提供权限、血缘、标签和跨工作区访问。对机器学习数据层来说,它解决三个具体问题:
- 命名空间隔离:用
ml_dev、ml_stage、ml_prod三个 catalog 区分环境,避免开发表被误用于生产训练。 - 权限收敛:特征表通常只允许特征平台服务账号写入,训练与推理角色只读,权限通过
GRANT SELECT ON TABLE授予。 - 血缘追踪:从原始事件表到特征表再到模型,Unity Catalog 自动记录表级与列级血缘,便于定位特征漂移来源。
一个可落地的权限与标签示例:
GRANT USE CATALOG ON CATALOG ml_prod TO `ml-trainer`;
GRANT USE SCHEMA ON SCHEMA ml_prod.features TO `ml-trainer`;
GRANT SELECT ON TABLE ml_prod.features.user_behavior TO `ml-trainer`;
ALTER TABLE ml_prod.features.user_behavior
SET TAGS ('domain' = 'user', 'owner' = 'feature-platform', 'sla' = 'daily-06:00');
标签不是装饰,它让特征检索、成本归因和 SLA 监控可以按 domain 或 owner 聚合。当特征数量增长到数百张表时,没有标签体系几乎无法治理。
特征表:离线与在线的一致组织
Databricks 特征表在 Delta 表之上增加了特征元数据与在线存储同步能力。其数据组织通常包含三部分:
- 主键:如
user_id,用于在线点查。 - 时间戳键:如
feature_ts,用于离线 point-in-time 关联,防止标签泄漏。 - 特征列:如
click_cnt_7d、order_amt_30d,需带明确的类型与默认值。
离线训练时,用 create_training_set 按标签时间戳关联特征快照;在线推理时,特征表把最新版本同步到在线存储(如 DynamoDB、Cosmos DB 或在线 Delta 表),由模型服务按主键读取。关键约束是:离线与在线必须来自同一份特征定义,否则会出现训练-服务偏差。
三层协同的数据流
把三者串起来看,数据从原始事件进入 Delta 表,经特征计算写入特征表,由 Unity Catalog 统一登记与授权,训练和推理分别从离线快照与在线存储读取。下图展示了这一纵向结构与关键接口。
数据组织中的关键参数与判断依据
在真实项目中,数据层是否健康可以通过几个可观测点判断:
| 观察项 | 合理范围(示例) | 异常含义 |
|---|---|---|
| 特征表小文件数 | 单分区 < 50 个 | 写入过碎,需 OPTIMIZE |
| 离线/在线特征差异率 | < 0.1% | 存在训练-服务偏差 |
| 特征新鲜度延迟 | ≤ SLA 窗口 | 上游计算或同步失败 |
| 无标签泄漏校验 | feature_ts ≤ label_ts | 关联逻辑错误 |
这些指标应写入特征表的标签或监控表,由 Unity Catalog 的标签体系聚合,而不是散落在各团队的脚本里。数据层架构设计的最终目标,是让“同一份特征定义”在离线训练与在线推理之间保持可验证的一致性,同时让权限、血缘和成本都能被统一治理。