Spark ML ALS推荐算法为何返回用户已观看的项目?
为什么Spark ALS推荐会包含用户已观看的项目?
嘿,这个问题我之前做推荐系统的时候也踩过坑!其实Spark ML里的ALS算法默认就是不会自动排除用户已经交互过的项目的,原因主要有这几点:
- 核心逻辑未内置历史过滤:ALS的
recommendForAllUsers方法本质是基于用户和物品的隐因子向量计算预测评分,然后返回每个用户评分最高的N个物品。它完全不会去比对你的training数据集里的历史交互记录——哪怕某个电影是用户已经看过的,只要模型算出的预测评分够高(比如用户之前给过五星,模型预测分也拉满),就会被放进推荐结果里。 - 设计上的灵活性考量:Spark把是否过滤历史交互的决定权交给了开发者。毕竟有些场景是需要推荐重复内容的——比如视频平台用户可能会反复刷喜欢的老剧,所以ALS不硬做过滤,让你根据业务需求自行处理。
解决办法:手动过滤历史交互记录
要得到只包含新项目的推荐,你需要把用户的历史观看数据和推荐结果做一次过滤,用Spark的DataFrame操作就能轻松实现。以下是Python版的示例代码:
from pyspark.sql import functions as F # 1. 提取用户的历史观看记录(去重,避免重复过滤) user_history = training.select("userId", "movieId").distinct() # 2. 展开推荐结果,把嵌套的recommendations字段拆成单行数据 user_recs_exploded = userRecs.select( "userId", F.explode("recommendations").alias("rec") ).select( "userId", F.col("rec.movieId").alias("recommended_movieId"), F.col("rec.rating").alias("predicted_rating") ) # 3. 用左反连接过滤掉用户已经看过的电影 # 左反连接会保留user_recs_exploded中不在user_history里的记录 filtered_recs = user_recs_exploded.join( user_history, (user_recs_exploded["userId"] == user_history["userId"]) & (user_recs_exploded["recommended_movieId"] == user_history["movieId"]), how="left_anti" ) # 4. 重新按用户分组,取预测评分最高的Top 10作为最终推荐 final_user_recs = filtered_recs.groupBy("userId").agg( F.sort_array(F.collect_list(F.struct("predicted_rating", "recommended_movieId")), ascending=False).alias("recommendations") ).select("userId", "recommendations")
这样处理之后,final_user_recs里就只会包含用户没看过的新项目啦!
内容的提问来源于stack exchange,提问作者peleitor
相关产品推荐
相关产品推荐

