1. 项目概述
这个基于Django框架和协同过滤算法的电影推荐系统,是我在开发在线视频平台时实际落地的一个项目。它解决了传统影视网站"千人一面"的内容展示问题,能够根据用户历史行为智能推荐可能感兴趣的电影。
推荐系统的核心价值在于:当平台片库达到万部级别时,用户靠手动翻页根本找不到想看的内容。我们实测数据显示,接入推荐系统后用户平均观看时长提升了37%,会员转化率提高了22%。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 Django框架选型考量
选择Django主要基于三个实际考量:
- 自带Admin后台能快速管理电影数据
- ORM系统简化了用户行为数据的存储查询
- 完善的Auth模块直接复用用户系统
在项目目录结构上,我采用这样的组织方式:
code复制recommend_system/
├── movies/ # 电影模型和视图
├── users/ # 用户认证模块
├── algo/ # 推荐算法实现
└── templates/ # 前端展示模板
2.2 协同过滤算法实现
我们测试过两种协同过滤方案:
- 基于用户的协同过滤(UserCF):适合用户量大的场景
- 基于物品的协同过滤(ItemCF):适合物品稳定的场景
最终选择ItemCF,因为电影库更新频率低于用户增长。核心计算公式如下:
code复制相似度计算(余弦相似度):
sim(i,j) = ∑(R(u,i)×R(u,j)) / √(∑R(u,i)² × ∑R(u,j)²)
预测评分:
P(u,i) = ∑[sim(i,j)×R(u,j)] / ∑|sim(i,j)|
在Django中的具体实现:
python复制# algo/recommend.py
from math import sqrt
def cosine_sim(movie1, movie2):
# 获取对两个电影都有评分的用户
common_users = set(movie1.ratings.all().values_list('user', flat=True)) &
set(movie2.ratings.all().values_list('user', flat=True))
sum_xx, sum_yy, sum_xy = 0, 0, 0
for user in common_users:
r1 = movie1.ratings.get(user=user).score
r2 = movie2.ratings.get(user=user).score
sum_xx += r1*r1
sum_yy += r2*r2
sum_xy += r1*r2
denominator = sqrt(sum_xx) * sqrt(sum_yy)
return sum_xy/denominator if denominator else 0
3. 关键实现细节
3.1 数据模型设计
电影和用户评分是系统的核心数据,模型设计如下:
python复制# movies/models.py
from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=200)
genres = models.CharField(max_length=100) # 用|分隔的类型
year = models.IntegerField()
class Rating(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
score = models.FloatField() # 1-5分
timestamp = models.DateTimeField(auto_now_add=True)
3.2 推荐流程优化
原始ItemCF算法存在计算量大的问题,我们做了三点优化:
- 滑动时间窗口:只计算最近3个月的用户行为
- 相似度缓存:每天凌晨计算并存储电影相似度矩阵
- 热门降权:对《肖申克的救赎》这类大众电影做降权处理
优化前后性能对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 计算耗时 | 4.2小时 | 28分钟 |
| 内存占用 | 16GB | 3.2GB |
| 推荐响应时间 | 1200ms | 180ms |
4. 部署实践
4.1 生产环境配置
推荐系统对计算资源要求较高,我们的服务器配置:
- CPU: 8核(主要消耗在相似度计算)
- 内存: 16GB(存储相似度矩阵)
- 数据库: PostgreSQL(Django配置示例)
python复制# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'recommend_db',
'USER': 'db_user',
'PASSWORD': 'complexpassword123',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
4.2 冷启动解决方案
新电影或新用户没有足够行为数据时,采用混合推荐策略:
- 基于内容过滤(电影类型/导演/演员)
- 热门排行榜补位
- 随机试探性推荐(收集用户反馈)
5. 踩坑实录
5.1 相似度矩阵爆炸
初期全量计算导致内存溢出,解决方案:
- 只保留每个电影Top50相似项
- 使用稀疏矩阵存储格式
- 分片计算(按电影类型分组)
5.2 实时性瓶颈
用户最新行为无法立即影响推荐,最终方案:
- 短期兴趣:用Redis存储最近10次点击
- 长期兴趣:每日离线计算
- 混合权重:短期兴趣占30%权重
6. 效果评估指标
我们建立了完整的A/B测试体系:
- 点击率(CTR)
- 推荐覆盖率(推荐了多少独特电影)
- 惊喜度(推荐非热门电影的比例)
- 用户满意度调查(五星评分)
典型优化案例:当发现战争片推荐过多时,通过调整类型权重参数,使得类型分布更均衡。
