4、经典召回策略(下):基于内容的召回、基于图的召回(PersonalRank)、热点与冷启动召回
好,咱们接着聊召回策略的下半场。上一章讲了协同过滤和向量化召回,这一章我重点说说另外三个实战中绕不开的策略:基于内容的召回、基于图的PersonalRank,以及热点与冷启动召回。
说实话,这三个策略在工业界的使用频率非常高。尤其是冷启动,几乎每个新上线的推荐系统都会遇到。我个人习惯把这三类策略称为「兜底三件套」——当你的协同过滤和向量召回效果不佳时,它们往往能救场。
4.1 基于内容的召回:从物品本身找线索
基于内容的召回,说白了就是「物以类聚」。我们不看用户行为,只看物品本身的属性。比如一篇新闻,它的标题、正文、标签、分类,这些就是它的「内容特征」。
我在项目中遇到过这样一个场景:一个新用户刚注册,没有任何行为记录。协同过滤直接歇菜。但基于内容的召回可以工作——只要用户选了「我喜欢科技类文章」,我们就能把科技类的内容推给他。
核心思路:
- 为每个物品构建特征向量(TF-IDF、Word2Vec、BERT embedding等)
- 为用户构建兴趣画像(根据历史行为物品的特征加权平均)
- 计算用户画像与候选物品的相似度,取TopN召回
举个简单的例子,假设我们有一篇电影《盗梦空间》,它的特征向量可能是:
{
"genre": ["科幻", "悬疑", "动作"],
"director": "诺兰",
"actors": ["小李子", "渡边谦"],
"keywords": ["梦境", "潜意识", "时间"]
}
用户A看过《星际穿越》和《记忆碎片》,那他的画像里「诺兰」这个导演的权重就会很高。基于内容的召回就会把《盗梦空间》排到前面。
关键点:基于内容的召回有个天然优势——可解释性强。你可以直接告诉用户「因为您喜欢诺兰导演的作品,所以推荐了《盗梦空间》」。这在很多业务场景下非常重要。
但缺点也很明显:它容易陷入「信息茧房」。用户只看过科幻片,你就一直推科幻片,用户永远看不到其他类型的好内容。所以它通常只作为召回路之一,不能独占。
4.2 基于图的召回:PersonalRank算法
接下来这个算法,我个人非常喜欢。PersonalRank,本质上是在用户-物品二部图上做随机游走。
你想想看,用户和物品之间天然就是一个图结构。用户点击了物品,就形成了一条边。PersonalRank的思路是:从一个用户节点出发,在图上随机游走,游走过程中经过的物品节点,就是该用户可能感兴趣的物品。
算法流程:
- 初始化:给目标用户u的节点赋初始分1.0,其他节点赋0
- 开始迭代:每个节点以概率α继续游走,以概率(1-α)回到起点
- 游走规则:从当前节点随机选择一条边,走到邻居节点
- 收敛后,所有物品节点的得分就是该用户的推荐分数
代码实现其实不复杂,我贴一个简化版:
def personal_rank(graph, user_id, alpha=0.85, max_iter=100):
"""
graph: 用户-物品二部图,格式 {node: {neighbor: weight}}
user_id: 目标用户
alpha: 游走概率
"""
rank = {node: 0 for node in graph}
rank[user_id] = 1.0
for _ in range(max_iter):
new_rank = {node: 0 for node in graph}
for node in graph:
if rank[node] == 0:
continue
# 以alpha概率游走
for neighbor, weight in graph[node].items():
new_rank[neighbor] += alpha * rank[node] * weight / len(graph[node])
# 以(1-alpha)概率回到起点
new_rank[user_id] += (1 - alpha) * rank[node]
rank = new_rank
# 只返回物品节点的得分
return {node: score for node, score in rank.items() if node.startswith('item_')}
避坑指南:我曾经在线上部署PersonalRank时踩过一个坑——图太大,迭代收敛太慢。后来我做了两个优化:一是只保留用户最近30天的行为构建子图;二是用矩阵运算替代循环迭代。效果立竿见影,耗时从秒级降到了毫秒级。
PersonalRank的好处是能捕捉到「间接关联」。比如用户A和用户B都看过《星际穿越》,用户B还看过《肖申克的救赎》,那PersonalRank就有可能把《肖申克的救赎》推荐给用户A。这种「二度关联」是协同过滤做不到的。
4.3 热点召回:流量分发的基本盘
热点召回,听起来简单,但做起来门道不少。说白了就是把当前最热的内容推给用户。但「热」怎么定义?
我个人习惯用综合热度分:
hot_score = 0.4 * log(click_7d + 1) + 0.3 * log(like_7d + 1) + 0.2 * log(share_7d + 1) + 0.1 * log(comment_7d + 1)
这里用log是为了防止某个指标爆炸性增长。比如一个视频突然爆火,点击量从100涨到100万,如果不做log处理,其他指标就完全被淹没了。
热点召回的几个要点:
- 时间衰减:7天前的热度要打折,我一般用指数衰减
- 去重:同一个热点事件可能有多个相似内容,只保留一个
- 多样性:不能全是娱乐热点,要兼顾科技、体育、财经等类别
注意:热点召回虽然简单,但千万别把它当成主力。我见过一些团队把热点召回放在第一位,结果用户看到的全是千篇一律的爆款内容,用户留存反而下降了。热点召回更适合作为「补充策略」,占比控制在10%-20%比较合理。
4.4 冷启动召回:新用户和新物品的救星
冷启动,这是推荐系统里最头疼的问题之一。没有之一。
冷启动分两种:用户冷启动和物品冷启动。
用户冷启动:新用户来了,没有任何行为记录。怎么办?
- 基于人口统计学:年龄、性别、地域、设备型号等
- 基于注册信息:用户选择的兴趣标签
- 基于社交关系:如果允许,可以看用户的好友喜欢什么
- 基于设备指纹:同一设备上的历史用户行为可以借鉴
我在项目中用过一种比较巧妙的方法——冷启动探索池。把新内容按类别均匀分成若干组,新用户注册时随机分配一组。等用户产生了一些行为后,再切换到个性化推荐。这样既保证了新用户有内容可看,又为后续的个性化积累了数据。
物品冷启动:新内容上线了,没人看过,怎么推?
- 基于内容特征:用新物品的内容特征匹配用户画像
- 基于创作者历史:如果创作者之前的内容表现好,新内容也值得一试
- 基于探索策略:给新物品一定的「曝光配额」,比如前1000次曝光免费
核心原则:冷启动的本质是「用探索换信息」。你给新用户推一些内容,用户点击或不点击,都是在给你提供信息。所以冷启动策略要设计得足够「宽容」——允许试错,允许低点击率,只要信息能快速积累起来。
4.5 三种策略的对比与组合
最后,我整理了一张对比表,方便你快速理解:
| 策略 | 核心思想 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 基于内容 | 物品属性相似 | 新用户、长尾物品 | 可解释性强、无冷启动问题 | 信息茧房、特征工程复杂 |
| PersonalRank | 图上随机游走 | 用户行为稀疏 | 能捕捉间接关联 | 计算量大、图构建复杂 |
| 热点召回 | 全局热度排序 | 新用户、时效性内容 | 简单高效、覆盖面广 | 个性化弱、容易同质化 |
在实际的推荐系统中,这三种策略通常是多路召回的关系。每一路召回一个TopN列表,然后通过排序模型融合。我个人习惯的做法是:
- 基于内容召回:占30%
- PersonalRank召回:占20%
- 热点召回:占15%
- 协同过滤/向量召回:占35%
当然,这个比例不是固定的。不同业务、不同阶段,比例要动态调整。比如新用户多的时候,冷启动和热点的比例就要调高。
嗯,这一章的内容就到这里。下一章我们聊聊排序模型——从粗排到精排,再到重排,整个排序链路怎么设计。到时候见。