1. 实时特征计算概述
大家好,我是你们的讲师。今天咱们正式开始《实时召回特征计算与存储》的第一章。说实话,每次讲这门课的开头,我都会想起自己刚接触推荐系统时的一个困惑:特征到底是怎么从原始日志变成模型能用的东西的? 这个过程,就是特征计算的核心。
这一章,我们先搭个框架。搞清楚实时特征计算在整个推荐系统里到底扮演什么角色,它和离线特征有什么本质区别。嗯,这部分概念虽然基础,但很多线上事故的根源,恰恰是对这些基础认知的偏差。
1.1 实时推荐系统架构概览
我们先看一张图。这是我个人习惯用的一个简化架构,去掉了那些花哨的组件,只保留最核心的链路。
核心观点: 实时推荐系统,说白了就是一条「数据进,结果出」的流水线。特征计算是这条流水线的中游枢纽。
你想想看,用户点了一个商品,这个行为从产生到影响下一次推荐结果,中间经历了什么?
- 数据源层:行为日志被采集,发送到消息队列(比如 Kafka)。
- 特征计算层:消费消息,计算用户实时兴趣标签、物品实时热度等。
- 特征存储层:把计算结果写入高速缓存,覆盖旧值。
- 召回层:当用户发起请求时,直接从缓存读取最新特征,进行检索。
我在项目中遇到过好几次,团队花了大把精力优化召回模型,结果线上效果纹丝不动。最后排查下来,是特征计算延迟太高,模型拿到的都是几分钟前的「过期」特征。所以,特征计算是整个系统的「水龙头」——水龙头没拧开,后面管道再粗也没用。
1.2 特征计算在推荐链路中的位置
我们再把镜头拉近一点,看看特征计算具体卡在哪个环节。
一条完整的推荐链路,通常分为四个阶段:
| 阶段 | 核心任务 | 特征计算角色 |
|---|---|---|
| 数据接入 | 采集、清洗、格式化原始数据 | 定义特征来源和原始字段 |
| 特征计算 | 聚合、变换、拼接、存储特征 | 核心执行者 |
| 召回 | 从海量物品中筛选候选集 | 提供用户侧和物品侧特征 |
| 排序 | 对候选集精排打分 | 提供更丰富的交叉特征 |
你会发现,特征计算是唯一一个同时服务召回和排序的模块。而且,召回阶段对特征实时性的要求比排序更高。为什么?
排序阶段通常有几百个候选物品,可以容忍几百毫秒的延迟。但召回阶段面对的是千万级物品库,如果特征延迟导致召回结果「冷启动」或「兴趣漂移」,用户刷到的内容就会变得莫名其妙。
我的经验: 在搭建特征计算服务时,我建议把召回特征和排序特征分开存储。召回特征追求极致的读取速度(通常用 Redis 的 Hash 结构),排序特征可以容忍稍慢的读取,但需要更丰富的维度。混在一起存储,容易互相拖累。
1.3 实时 vs 离线特征对比
好了,到了这一节最核心的对比。很多同学会问:「离线跑批算特征不香吗?为什么非要实时计算?」
我们直接看对比表:
| 对比维度 | 离线特征 | 实时特征 |
|---|---|---|
| 计算时机 | T+1 或小时级定时调度 | 事件触发,秒级/毫秒级响应 |
| 数据源 | Hive 表、离线数仓 | Kafka 流、实时日志 |
| 典型特征 | 用户长期偏好、物品基础属性 | 用户最近点击序列、实时热度 |
| 存储介质 | HDFS、HBase | Redis、内存网格 |
| 一致性要求 | 强一致(最终一致即可) | 最终一致(允许短暂不一致) |
| 计算复杂度 | 高(可跑复杂模型) | 低(必须轻量快速) |
| 典型延迟 | 分钟级 ~ 小时级 | 毫秒级 ~ 秒级 |
看到这里,你可能会想:「那是不是所有特征都应该实时化?」
千万别这么干。我曾经在一个项目里,试图把用户的「性别」「年龄」这类静态属性也做成实时特征。结果呢?计算逻辑没变,只是把数据源从 Hive 换成了 Kafka,白白增加了维护成本和延迟。这类特征,离线算好存起来,线上直接读,完全够用。
避坑指南: 我曾经犯过一个错误——把离线特征和实时特征放在同一个特征服务里,用同一个 key 覆盖存储。结果离线任务因为数据倾斜延迟了 30 分钟,导致实时特征被离线特征「回刷」成了旧值。线上推荐效果直接跳水。后来我学乖了:离线特征和实时特征必须用不同的 key 前缀,或者干脆分服务部署。
那么,什么样的特征适合实时计算?我总结了三类:
- 用户短期行为序列:最近 5 分钟点击、最近 1 小时搜索词。这类特征时效性极强,离线算出来已经「凉了」。
- 物品实时统计量:实时点击率、实时曝光量。用于捕捉突发热点。
- 上下文特征:当前时间、用户网络环境、设备状态。这些特征只能在请求时实时获取。
而像「用户会员等级」「物品类目」「历史 CTR 均值」这类变化缓慢的特征,老老实实用离线计算就好。
1.4 本章小结
这一章我们主要理清了三个问题:
- 实时特征计算在架构中的位置:它是数据源和召回/排序之间的桥梁,决定了推荐系统能否「跟上」用户的变化。
- 特征计算服务于召回和排序,但召回对实时性的要求更苛刻。
- 实时特征和离线特征各有适用场景,不能一刀切。核心原则是:变化快的特征实时算,变化慢的特征离线算,两者隔离存储。