3. 离线特征系统架构:批处理架构
离线特征系统是特征工程体系中最成熟、最稳定的部分。其核心采用 Lambda 架构的批处理层,以“全量计算、周期调度、不可变存储”为设计原则,为模型训练和批量推理提供高一致性的特征数据。本章深入剖析批处理层的架构设计、存储选型与计算流程。
3.1 Lambda 架构中的批处理层
Lambda 架构将数据流分为批处理层(Batch Layer)、速度层(Speed Layer)和服务层(Serving Layer)。离线特征系统对应 批处理层,承担以下职责:
- 全量数据重算:每次调度周期(如每日凌晨)读取全量历史数据,重新计算所有特征,保证结果可复现。
- 数据不可变:原始数据以 append-only 方式存储,批处理层输出结果写入不可变存储,支持时间旅行查询。
- 高一致性:通过事务性写入和幂等计算,确保同一份数据在不同时间重算结果完全一致。
- 容错与重试:任务失败后可从检查点(Checkpoint)恢复,或基于原始数据全量重跑。
关键设计原则:批处理层是“真相之源”(Source of Truth)。所有实时特征在回放验证时,必须以批处理层产出的离线特征为基准进行比对。
3.2 离线特征存储:Hive / HDFS
离线特征存储选型以 Hive 表 + HDFS 文件 为事实标准。其核心优势在于:
| 维度 | Hive / HDFS | 备选方案(如 HBase) |
|---|---|---|
| 存储模型 | 列式 ORC / Parquet,高压缩比 | 宽表存储,行式访问 |
| 查询模式 | 批量扫描、分区裁剪 | 点查、小范围扫描 |
| 一致性 | ACID(Hive 4+),快照隔离 | 最终一致性 |
| 成本 | 低成本,基于 HDFS 副本 | 高内存成本 |
| 适用场景 | 全量特征回放、训练集构建 | 在线特征服务 |
离线特征表通常按 日期分区(如 dt=2025-03-01),每个分区内存储该日所有实体的特征快照。典型表结构如下:
CREATE TABLE offline_user_features (
user_id STRING,
feature_date STRING,
age INT,
city STRING,
last_7d_click_cnt INT,
last_7d_order_amt DOUBLE,
-- ... 其他特征列
update_time TIMESTAMP
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET
TBLPROPERTIES ('parquet.compression'='SNAPPY');
分区策略建议:使用
dt 作为分区键,避免使用 feature_date 作为分区字段。前者是 Hive 保留字,性能更优;后者可能导致小文件过多。
3.3 离线特征计算流程
离线特征计算遵循 ETL 管道 模式,分为三个核心阶段:数据接入、特征计算、结果写入。以下 SVG 图展示了完整的批处理架构与数据流。
3.4 批处理计算流程详解
一个典型的离线特征批处理任务包含以下步骤,以每日凌晨 T+1 调度为例:
- 数据读取:从 HDFS 原始层读取前一日(dt = yesterday)的全量业务日志,包括用户行为、订单、点击等。
- 数据清洗:过滤异常数据(如空 user_id、时间戳越界),去重(基于事件 ID 去重),格式统一。
- 窗口聚合:按用户 ID 分组,计算滑动窗口特征(如近 7 天点击次数、近 30 天消费金额)。窗口边界由业务定义,通常使用 Spark SQL 的
RANGE BETWEEN或自定义 UDAF。 - 特征拼接:将多个窗口特征、基础属性特征、交叉特征拼接为宽表,每行对应一个用户在某日的特征快照。
- 质量校验:检查空值率、特征分布是否漂移、主键是否唯一。若校验失败,触发告警并阻断下游写入。
- 分区写入:将结果写入 Hive 表对应分区(dt = yesterday),使用
INSERT OVERWRITE保证幂等性。
常见陷阱:窗口聚合时若使用
UNBOUNDED PRECEDING 可能导致数据倾斜。建议对高频用户做分桶处理,或使用 RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW 限定窗口范围。
3.5 离线特征与实时特征回放对比的架构映射
在特征回放场景中,离线特征系统作为 基准系统,为实时特征提供“标准答案”。以下表格对比两者在批处理层中的角色差异:
| 对比维度 | 离线特征(批处理层) | 实时特征(速度层) |
|---|---|---|
| 计算时间 | T+1 批量计算 | 事件发生后毫秒级 |
| 数据范围 | 全量历史数据 | 近期窗口数据(如 7 天) |
| 一致性 | 强一致性,可重算 | 最终一致性,可能丢数据 |
| 存储 | Hive ORC / Parquet | Redis / HBase / Kafka |
| 回放角色 | 基线(Ground Truth) | 待验证对象 |
回放验证时,离线特征系统提供 全量历史快照,实时特征系统按相同时间窗口回放事件流,两者在特征值层面逐字段比对。任何偏差都会触发告警,驱动实时计算逻辑修正。
最佳实践:在离线特征表中增加
feature_version 列,记录特征计算逻辑的版本号。回放时,实时特征必须使用相同版本的计算逻辑,避免因逻辑变更导致误报。