1. 项目概述:基于协同过滤的电影推荐系统
这个电影推荐系统项目采用Python+Django技术栈,核心算法是协同过滤(Collaborative Filtering)。我在实际开发中发现,这种组合特别适合中小型推荐场景——Django自带的管理后台能快速搭建数据录入界面,而Python丰富的科学计算库让算法实现变得轻松。
系统工作原理很简单:通过分析用户的历史评分数据,找到兴趣相似的用户群体(用户协同过滤),或者发现电影之间的关联性(物品协同过滤)。比如用户A和B都喜欢《肖申克的救赎》和《阿甘正传》,那么当B给《当幸福来敲门》打了高分时,系统就会把这部电影推荐给A。
注意:协同过滤算法存在"冷启动"问题——新用户或新物品没有足够历史数据时难以产生推荐。实际项目中我通常会混合内容推荐(如电影类型、导演)作为补充方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心算法解析与实现
2.1 协同过滤算法选型
我选择了基于用户的协同过滤(UserCF),因为电影推荐场景中用户兴趣往往比物品特性更稳定。核心公式是计算用户相似度:
python复制from sklearn.metrics.pairwise import cosine_similarity
def calculate_user_similarity(user_ratings):
# user_ratings是用户-电影评分矩阵
return cosine_similarity(user_ratings)
实测发现,当用户量超过1万时,内存中的相似度矩阵会暴涨。这时我的优化方案是:
- 使用稀疏矩阵存储(scipy.sparse)
- 只保留每个用户Top20的相似用户
- 定时离线计算相似度(Celery定时任务)
2.2 评分预测与推荐生成
获得相似用户后,用加权平均预测目标用户对未观看电影的评分:
python复制def predict_rating(target_user, movie, user_sim, user_ratings):
similar_users = user_sim[target_user].argsort()[-10:][::-1]
weighted_sum = 0
sim_sum = 0
for user in similar_users:
if user_ratings[user][movie] > 0:
weighted_sum += user_sim[target_user][user] * user_ratings[user][movie]
sim_sum += user_sim[target_user][user]
return weighted_sum / sim_sum if sim_sum != 0 else 0
避坑提示:一定要处理除零错误!新用户或冷门电影可能导致相似度总和为零。
3. Django系统架构设计
3.1 数据模型设计
python复制from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=200)
genres = models.CharField(max_length=200) # 用"|"分隔类型
year = models.IntegerField()
class Rating(models.Model):
user_id = models.IntegerField(db_index=True)
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
rating = models.FloatField()
timestamp = models.DateTimeField()
数据库优化技巧:
- 为user_id创建索引(查询频率高)
- 使用select_related减少电影信息查询次数
- 定期归档冷数据到历史表
3.2 推荐API实现
python复制from rest_framework.decorators import api_view
@api_view(['GET'])
def get_recommendations(request, user_id):
# 1. 从缓存读取推荐结果
cache_key = f"rec_{user_id}"
cached = cache.get(cache_key)
if cached:
return Response(cached)
# 2. 实时计算(降级方案)
recommendations = calculate_recommendations(user_id)
# 3. 异步更新缓存
update_cache.delay(user_id)
return Response(recommendations)
4. 性能优化实战记录
4.1 缓存策略设计
我采用三级缓存架构:
- 内存缓存(Redis):存储实时推荐结果(TTL=1小时)
- 分布式缓存(Memcached):存储用户相似度矩阵
- 预计算存储(MySQL):全量用户推荐结果(每日更新)
实测QPS从50提升到2000+的配置:
python复制CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"MAX_ENTRIES": 10000
}
}
}
4.2 数据库优化
当用户评分数据达到百万级时,我遇到了严重的查询延迟。通过EXPLAIN分析发现全表扫描问题,最终优化方案:
- 创建复合索引:
sql复制CREATE INDEX idx_user_movie ON ratings(user_id, movie_id);
- 数据分片:
- 按user_id范围分表(user_ratings_0~user_ratings_9)
- 使用Django路由数据库
python复制class RatingRouter:
def db_for_read(self, model, **hints):
if model == Rating:
return f'ratings_{hints["user_id"] % 10}'
5. 部署与监控方案
5.1 生产环境部署
我的标准部署架构:
- Nginx:负载均衡+静态文件
- Gunicorn:Django应用服务器
- Supervisor:进程管理
- Prometheus+Grafana:监控看板
关键配置示例(gunicorn.conf):
python复制workers = 2 * cpu_count() + 1
worker_class = 'gevent'
keepalive = 5
timeout = 30
5.2 推荐质量监控
除了系统性能,我还建立了推荐质量评估体系:
- 离线评估(每日运行):
- 准确率:RMSE、MAE
- 覆盖率:推荐物品占比
- 新颖度:推荐物品的平均热度
- 线上AB测试:
- 点击率(CTR)
- 转化率(观看时长>50%)
- 用户留存率
实现代码片段:
python复制def calculate_rmse(predictions, test_set):
squared_errors = [(pred - actual)**2
for pred, actual in predictions]
return math.sqrt(sum(squared_errors) / len(squared_errors))
6. 常见问题排查手册
6.1 冷启动问题解决方案
- 混合推荐策略:
python复制def hybrid_recommend(user_id):
if is_new_user(user_id):
return popular_movies() # 返回热门电影
else:
return cf_recommend(user_id)
- 利用元数据:
- 新用户注册时选择感兴趣的类型
- 用电影导演/演员信息补充推荐
6.2 内存溢出处理
当用户量增长时,相似度矩阵可能导致OOM。我的解决方案:
- 分块计算:
python复制from joblib import Parallel, delayed
def chunked_similarity(ratings, chunk_size=1000):
n_users = ratings.shape[0]
return Parallel(n_jobs=4)(
delayed(cosine_similarity)(
ratings[i:i+chunk_size], ratings
) for i in range(0, n_users, chunk_size)
)
- 使用近似算法:
- MinHash
- Locality-Sensitive Hashing (LSH)
7. 项目扩展方向
在实际运营中,我逐步增加了这些功能:
- 实时推荐:
- 用Kafka处理用户实时行为
- Flink流式计算更新推荐列表
- 深度学习增强:
python复制import tensorflow as tf
from tensorflow_recommenders import tasks
model = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size=1000, output_dim=64),
tf.keras.layers.Dense(64, activation='relu'),
tasks.Ranking()
])
- 多模态推荐:
- 分析电影海报视觉特征
- 处理用户评论情感倾向
这个项目让我深刻体会到,推荐系统不是一劳永逸的工程,需要持续迭代算法、优化性能,并紧密结合业务需求。比如我们曾发现周末的推荐效果明显变差,后来分析是因为用户休闲时的观影偏好与工作日不同,于是增加了时间上下文特征后效果显著提升。
