3. 批处理特征计算

在特征工程体系中,批处理特征计算承担着“历史沉淀”的角色。它面向全量或大时间跨度数据,按固定周期(如天、小时)产出稳定、可回溯的离线特征,是训练样本生成与特征回填的主力。与流式特征相比,批处理更强调吞吐、正确性与可重算性,而非毫秒级延迟。理解批处理架构、Spark/Flink Batch 计算模式、离线聚合、窗口函数与特征衍生方法,是构建可靠 Feature Store 的基础。

核心原理:批处理架构与计算模式

批处理特征计算通常遵循“数据源 → 计算引擎 → 特征存储”的三段式架构。数据源多为 Hive、HDFS、对象存储或数据湖表;计算引擎负责聚合与衍生;结果写入 Feature Store 的离线表(Offline Store),供训练与批量推理读取。其核心诉求是幂等、可重跑、分区可追溯。

Spark 与 Flink Batch 是两种主流模式。Spark 以弹性分布式数据集(RDD/DataFrame)为核心,适合大规模全量聚合与复杂 SQL;Flink Batch 则复用流处理算子,在批模式下提供有界数据的有序处理,便于与流式特征共享逻辑。选择时需权衡团队技术栈、数据规模与流批一致性要求。

# Spark 批处理特征聚合示例(PySpark)
from pyspark.sql import functions as F

user_feat = (
    spark.table("dwd_user_behavior")
    .filter(F.col("dt").between("2024-01-01", "2024-01-31"))
    .groupBy("user_id")
    .agg(
        F.count("*").alias("pv_30d"),
        F.sum("amount").alias("gmv_30d"),
        F.countDistinct("item_id").alias("item_cnt_30d"),
        F.datediff(F.lit("2024-02-01"), F.max("dt")).alias("last_active_gap")
    )
)
user_feat.write.mode("overwrite").partitionBy("dt").saveAsTable("feat_user_30d")

方法流程:离线聚合与窗口函数

离线特征聚合的关键在于“分组维度 + 时间窗口 + 聚合函数”三要素。分组维度决定特征粒度(用户、商品、商户);时间窗口决定统计范围(近 7 天、近 30 天、自然月);聚合函数决定特征语义(计数、求和、均值、去重、最大最小值)。

窗口函数是批处理特征衍生的利器。它能在不改变行数的情况下,为每行数据附加滑动或滚动窗口统计值,常用于计算“用户最近一次行为距今天数”“近 3 次下单平均金额”等序列特征。Spark SQL 与 Flink SQL 均支持 OVER (PARTITION BY ... ORDER BY ... ROWS BETWEEN ...) 语法。

-- 使用窗口函数计算用户近3次下单平均金额
SELECT user_id, order_id, amount,
       AVG(amount) OVER (
           PARTITION BY user_id
           ORDER BY order_time
           ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
       ) AS avg_amt_last3
FROM dwd_order;
窗口函数与 GROUP BY 聚合的区别:前者保留明细行并附加统计列,适合序列衍生;后者压缩行数,适合宽表特征。实际生产中常先 GROUP BY 生成基础聚合,再用窗口函数做二次衍生。

案例场景:电商用户特征批处理链路

以电商场景为例,每日凌晨需产出用户 30 天行为特征。链路为:Hive 明细表 → Spark 按 user_id 聚合 → 窗口函数计算最近行为间隔 → 写入 Feature Store 离线表 → 训练样本关联。该链路需保证分区幂等,重跑时覆盖当日分区而非追加。

特征名称计算方式窗口更新周期
pv_30dcount(*)近30天每日
gmv_30dsum(amount)近30天每日
item_cnt_30dcountDistinct(item_id)近30天每日
last_active_gapdatediff(now, max(dt))全量每日
avg_amt_last3窗口均值近3次每日
批处理特征计算链路 数据源 Hive / 数据湖 计算引擎 Spark / Flink Batch 聚合与衍生 GROUP BY + 窗口 Feature Store 离线表 窗口函数衍生 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 近3次均值 / 最近行为间隔 / 序列趋势

误区与复盘

  • 误区一:全量重算代替增量。每次跑全量虽简单,但数据量大时成本高。应按分区增量计算,仅重跑受影响分区。
  • 误区二:忽略时间边界。窗口起止时间未对齐自然日,导致特征口径不一致。建议统一以业务日期分区。
  • 误区三:窗口函数滥用。在超大表上直接开窗易造成 Shuffle 倾斜。应先聚合缩减数据量,再开窗。
  • 误区四:特征与训练样本时间穿越。计算特征时使用了未来数据。必须严格按特征时间点截断。
批处理特征一旦写入 Feature Store,需记录特征版本与分区时间。训练时按样本时间关联对应分区,避免用最新特征回填历史样本造成标签泄漏。

综上,批处理特征计算的核心在于:以分区幂等为约束,以聚合与窗口为手段,以 Feature Store 为落点。掌握 Spark/Flink Batch 的计算模式与窗口衍生方法,才能让离线特征既稳定又可复用。