0

【完整版14章】ElasticSearch7+Spark 构建高匹配度搜索服务+千人千面推荐系统

学习园地星课it点top
2月前 10

获课:xingkeit.top/5543/


Spark 离线推荐模型:用户行为挖掘与偏好计算——一个数据挖掘工程师的“洞察”手记

如果用一句话总结我在离线推荐系统建设中的经验,那就是:“推荐模型的价值,不在于算法多先进,而在于你对用户行为的理解有多深。” 这不是一篇算法原理剖析,而是我在经历了无数轮模型迭代、A/B测试、以及“为什么推荐这么不准”的灵魂拷问后,沉淀下来的真实体感与思考。

一、离线推荐:被低估的“地基”

很多人聊推荐系统,张口就是深度学习、实时召回、在线排序。但我想说的是:离线推荐,是整个推荐系统的地基。地基不牢,上面盖什么都塌。

我接手第一个推荐项目时,团队把大量精力花在实时链路上,恨不得用户刚点完一个商品,下一秒就推荐类似的。结果呢?冷启动用户没有行为,推荐全是热门商品;长尾用户的行为稀疏,模型根本学不到个性化;半夜的离线任务跑不完,早上的在线服务用的是昨天的数据。

那次经历让我明白:离线推荐不是“离线”就低人一等,它承担着数据清洗、特征工程、基础召回、用户理解等最核心的职责。没有离线层的沉淀,在线层就是无源之水。

二、用户行为挖掘:从“日志”到“信号”

推荐模型的起点,不是算法,而是行为数据。

用户的每一次点击、浏览、收藏、购买、分享、差评,都是对商品/内容的一次“投票”。但如何把这些原始日志转化成模型能理解的信号,是个技术活。

我最早的做法很简单:点击算1分,购买算10分,收藏算5分。后来发现太粗糙了——用户在搜索结果页的点击,和在推荐位的点击,意图强度完全不同;用户花10秒浏览的商品,和花2分钟浏览的商品,兴趣浓度也不同。

于是我们引入了“行为权重”和“场景因子”。搜索点击权重低于推荐点击,因为搜索是主动意图,推荐是被动发现;长浏览权重高于短浏览,因为停留时长是兴趣浓度的直观体现;深夜的浏览权重高于白天,因为深夜的行为更接近真实偏好。

但这里有个陷阱:权重是主观的,需要数据验证。 我们曾经把一个品类的购买权重设得过高,结果推荐列表全是高价商品,CTR直接腰斩。后来我们用A/B测试反推权重——不同的权重策略跑小流量,看哪个组合带来的核心指标最优。用数据校准主观判断,是行为挖掘的底层逻辑。

另一个关键点是“负向信号”的利用。用户划过、不感兴趣、拉黑、取消收藏,这些行为同样有价值。早期我们只关注正向行为,推荐结果虽然相关,但缺少“多样性”和“惊喜感”。引入负向信号后,我们可以在召回阶段剔除用户明确不喜欢的品类,在排序阶段降低相关内容的权重。

三、偏好计算:从“行为”到“向量”

有了行为数据,下一步是把用户和物品映射到一个可计算的语义空间。这就是偏好计算的核心。

早期我们用“标签偏好矩阵”——用户对每个标签的偏好强度,等于用户对带有该标签的物品的行为加权和。这个方案简单直观,但有两个问题:一是标签体系需要人工维护,覆盖面有限;二是“标签”的语义太粗,无法表达“喜欢A品牌的运动鞋但不喜欢B品牌”这种细粒度偏好。

后来我们转向“Embedding向量”方案,用Word2Vec、Item2Vec或者Graph Embedding把用户和物品映射到低维向量空间。用户的偏好向量,就是其历史行为序列中物品向量的聚合。

这个转变让我对“偏好”有了新的理解:偏好不是一个“标签”,而是一个“位置”。 在向量空间里,用户的位置是由他所有行为物品的位置决定的。喜欢文艺片的用户离文艺片近,喜欢商业片的用户离商业片近。而推荐的任务,就是找到离用户最近的那些物品。

但Embedding不是万能的。它的冷启动问题比标签方案更严重——新用户没有行为序列,新物品没有历史交互,Embedding根本学不出来。我们的解决方案是“混合召回”:热门召回兜底冷启动,标签召回补充新物品,Embedding召回服务成熟用户和成熟物品。

四、Spark的角色:大数据时代的“肌肉”

离线推荐的计算量是惊人的。千万级用户、百万级物品、数十亿的行为记录,单机根本跑不动。Spark就是我们的大肌肉。

Spark在离线推荐中的作用,不是“算法创新”,而是“工程落地”。ALS(交替最小二乘法)做协同过滤,Spark MLlib有现成实现;特征工程中的聚合、Join、窗口计算,Spark DataFrame表达力强、执行效率高;Embedding的训练,Spark on YARN可以调度数百个core并行计算。

但我踩过一个坑:盲目追求“全量计算”。 早期我们的ALS模型每天全量重跑,用户行为矩阵几十亿条,训练一次要8小时。后来发现,用户行为的变化是增量式的,每天只有5%-10%的新数据。改成“增量更新”后,训练时间从8小时降到1.5小时,模型效果几乎没有下降。

另一个经验是“数据倾斜”的处理。用户行为天然是长尾分布的——头部用户的行为记录是尾部用户的成千上万倍。在Join操作时,头部用户会导致单个task处理数据量过大,拖慢整个任务。解决方案是加盐打散、广播小表、或者用Hive的bucket join提前预分区。这些Spark调优的技巧,在离线推荐这种大数据量场景下,比模型本身更影响产出效率。

五、离线评估:相信指标,但不迷信指标

模型好不好,不能靠感觉,要靠数据。离线推荐有一套成熟的评估指标:准确率、召回率、覆盖率、新颖度、多样性。

但我学到的教训是:指标可以优化,但用户的真实体验无法被指标完全量化。

有一次,我们优化了召回模型,离线AUC提升了2个百分点,覆盖率也提高了。满怀信心上线A/B测试,结果CTR没变,用户停留时长反而降了。分析后发现,新模型推了更多“相关但用户已经看过”的内容,离线评估只看“相关性”,没看“新鲜度”。用户觉得“又是这些”,就不想点了。

从那以后,我们的离线评估加入了“去重率”“新内容占比”“品类分散度”等辅助指标。虽然这些指标和最终业务指标不是严格正相关,但它们像“护栏”一样,防止模型走偏。

六、离线到在线:最后一公里的挑战

模型算出来了,怎么用?这是离线推荐容易被忽视的“最后一公里”。

我们的方案是:离线计算好的推荐结果(比如每个用户Top 200的物品列表),写入KV存储(Redis或HBase)。在线服务接到请求后,直接从KV中读取,不需要实时计算。这个方案延迟低、QPS高,但牺牲了实时性——用户刚产生的行为,要等到下一次离线任务才能生效。

对于需要实时响应的场景(比如用户刚点击了某个商品,希望立刻看到相关推荐),我们在在线层叠加了“实时补丁”——用户最近的几个行为,通过轻量级的实时召回(比如基于物品相似度的即时计算)补充到推荐列表中。

这种“离线兜底+实时增量”的架构,既保证了大部分场景的推荐质量,又兼顾了实时交互的体验。

七、写在最后:推荐是“理解”的艺术

做了这么多年推荐,我越来越觉得:推荐系统不是“算”出来的,是“理解”出来的。

你要理解用户的行为——什么是真正的兴趣,什么是偶然的点击;你要理解物品的特征——什么是核心属性,什么是营销包装;你要理解场景的上下文——用户是在打发时间,还是在认真购物;你甚至要理解人性——用户嘴上说不喜欢,但行为却很诚实。

Spark、算法、模型,这些都是工具。真正的价值,来自于你对这些“理解”的深度和准确度。

离线推荐虽然叫“离线”,但它离用户并不远。每一行Spark代码,最终都会变成用户手机上的一个推荐位。那个推荐位上的内容,可能影响用户的下一次消费、下一个决策、甚至下一段旅程。

这种“影响力”,是我持续优化推荐模型的动力。不是为了AUC提升0.1%,而是为了让用户在打开App的那一刻,看到的是“懂ta的”内容。

而这,大概就是推荐系统最朴素也最迷人的意义。



本站不存储任何实质资源,该帖为网盘用户发布的网盘链接介绍帖,本文内所有链接指向的云盘网盘资源,其版权归版权方所有!其实际管理权为帖子发布者所有,本站无法操作相关资源。如您认为本站任何介绍帖侵犯了您的合法版权,请发送邮件 [email protected] 进行投诉,我们将在确认本文链接指向的资源存在侵权后,立即删除相关介绍帖子!
最新回复 (0)

    暂无评论

请先登录后发表评论!

返回
请先登录后发表评论!