1. 项目概述
这个基于微信小程序的个性化电影推荐系统,是我在完成毕业设计时开发的一个实战项目。作为一个电影爱好者,我经常遇到"片荒"的困扰——面对海量电影资源却不知道看什么好。市面上的推荐系统要么过于简单,要么推荐结果不够精准。于是,我决定自己动手开发一个能真正理解用户喜好的智能推荐系统。
微信小程序作为载体有几个明显优势:首先,它无需安装,用户即用即走;其次,微信生态提供了丰富的社交功能,可以挖掘好友间的观影偏好;最重要的是,小程序开发门槛相对较低,适合个人开发者快速实现产品原型。
2. 系统架构设计
2.1 技术选型与整体架构
整个系统采用前后端分离的架构:
前端部分:
- 微信小程序原生开发(WXML+WXSS+JS)
- ECharts for WeChat 用于数据可视化
- Vant Weapp 组件库提升UI体验
后端部分:
- Spring Boot 2.7 作为基础框架
- MyBatis-Plus 3.5 处理数据持久化
- Redis 6.2 缓存热门推荐结果
- MongoDB 5.0 存储用户行为日志
推荐引擎:
- Python 3.8 + TensorFlow 2.6
- 协同过滤算法(UserCF和ItemCF)
- 基于内容的推荐(CB)
- 混合推荐策略
提示:选择Spring Boot是因为它对微信生态的兼容性好,MyBatis-Plus能大幅简化数据库操作,而Redis缓存可以显著提升推荐响应速度。
2.2 数据流设计
系统数据流分为三个主要环节:
数据采集层:
- 用户显式行为:评分、收藏、评论
- 用户隐式行为:浏览时长、暂停/快进
- 社交关系数据:微信好友观影动态
数据处理层:
- 实时计算:用户最近30分钟内的行为权重更高
- 离线计算:每晚2点全量更新用户画像
- 增量更新:每2小时更新一次推荐结果
服务输出层:
- 个性化推荐列表(主feed)
- 相似用户在看(社交推荐)
- 热门趋势(基于近期热度)
3. 核心功能实现
3.1 用户画像构建
用户画像是推荐系统的基石,我们设计了多维度的标签体系:
# 用户画像数据结构示例 user_profile = { "user_id": "wx123456", "basic_info": { "gender": "male", "age": 25 }, "preference": { "genres": ["科幻", "悬疑", "喜剧"], "directors": ["诺兰", "斯皮尔伯格"], "actors": ["莱昂纳多", "汤姆·汉克斯"] }, "behavior_pattern": { "watch_time": "21:00-23:00", "device": "iPhone", "network": "WiFi" }, "social_graph": { "close_friends": ["wx234567", "wx345678"], "influence_score": 0.75 } }构建过程分为三步:
- 冷启动阶段:通过问卷收集初始偏好
- 行为积累阶段:加权计算各类行为
- 动态调整阶段:引入时间衰减因子
3.2 推荐算法实现
3.2.1 协同过滤优化
传统协同过滤面临稀疏性问题,我们做了两点改进:
基于社交关系的权重调整:
最终评分 = 基础评分 × (1 + 0.2×好友相似度)时间衰减因子:
def time_decay(days): return math.exp(-0.05 * days) # 半衰期约14天
3.2.2 混合推荐策略
我们采用加权混合策略:
| 算法类型 | 权重 | 适用场景 |
|---|---|---|
| UserCF | 0.4 | 社交推荐 |
| ItemCF | 0.3 | 相似影片 |
| CB | 0.2 | 冷启动 |
| 热门推荐 | 0.1 | 新用户 |
# 混合推荐代码片段 def hybrid_recommend(user): uc_rec = user_cf(user) * 0.4 ic_rec = item_cf(user) * 0.3 cb_rec = content_based(user) * 0.2 hot_rec = hot_movies() * 0.1 return normalize(uc_rec + ic_rec + cb_rec + hot_rec)3.3 微信小程序关键实现
3.3.1 性能优化技巧
分页加载:
Page({ data: { movies: [], page: 1 }, onReachBottom() { this.setData({page: this.data.page + 1}) this.loadMoreData() } })缓存策略:
- 本地缓存:wx.setStorageSync('hot_movies', data)
- 图片懒加载:
请求合并:
// 使用Promise.all合并并行请求 Promise.all([ getRecommendations(), getFriendActivities() ]).then(([recs, activities]) => { // 更新UI })
3.3.2 社交功能实现
利用微信开放能力:
// 分享功能 onShareAppMessage() { return { title: '我发现了一部好电影', path: '/pages/movie/detail?id=' + this.data.movieId } } // 获取好友关系 wx.getFriendCloudStorage({ keyList: ['watchedMovies'], success(res) { console.log('好友数据', res.data) } })4. 数据库详细设计
4.1 核心表结构优化
除了基础的用户表和电影表,我们特别设计了:
用户行为日志表(user_behavior):
CREATE TABLE `user_behavior` ( `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` INT(11) NOT NULL, `movie_id` INT(11) NOT NULL, `behavior_type` TINYINT(4) NOT NULL COMMENT '1浏览 2播放 3评分 4收藏', `value` FLOAT DEFAULT NULL COMMENT '评分值/播放进度', `device_id` VARCHAR(64) DEFAULT NULL, `ip_address` VARCHAR(39) DEFAULT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_user_movie` (`user_id`, `movie_id`), INDEX `idx_time` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;推荐结果表(recommendation_results):
CREATE TABLE `recommendation_results` ( `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` INT(11) NOT NULL, `movie_id` INT(11) NOT NULL, `algorithm` VARCHAR(20) NOT NULL COMMENT 'ucf/icf/cb/hybrid', `score` FLOAT NOT NULL, `position` INT(11) NOT NULL COMMENT '推荐位次', `expire_time` TIMESTAMP NOT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_user_movie` (`user_id`, `movie_id`), INDEX `idx_user_score` (`user_id`, `score`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;4.2 查询优化实践
针对高频查询场景,我们采用以下优化方案:
热点数据缓存:
@Cacheable(value = "userRecs", key = "#userId") public List<Movie> getRecommendations(Integer userId) { // 数据库查询逻辑 }读写分离:
- 写操作:主库
- 读操作:从库 + 缓存
索引优化:
EXPLAIN SELECT * FROM user_behavior WHERE user_id = 123 AND created_at > '2023-01-01'
5. 部署与性能调优
5.1 服务器配置
我们使用阿里云ECS基础配置:
| 组件 | 配置 | 数量 |
|---|---|---|
| 应用服务器 | 2核4G,CentOS 7.9 | 2 |
| Redis | 1G内存,持久化开启 | 1 |
| MySQL | 4核8G,SSD磁盘 | 1主1从 |
| Python引擎 | 4核8G,GPU加速 | 1 |
5.2 压力测试结果
使用JMeter进行测试:
| 场景 | 并发数 | 平均响应时间 | 错误率 |
|---|---|---|---|
| 获取推荐列表 | 1000 | 238ms | 0.1% |
| 提交评分 | 500 | 156ms | 0% |
| 混合读写场景 | 800 | 342ms | 0.3% |
优化措施:
- 引入Hystrix实现熔断降级
- 调整Tomcat线程池参数
- 推荐结果预计算+缓存
6. 常见问题与解决方案
6.1 冷启动问题
现象:新用户没有历史行为数据,推荐质量差
解决方案:
- 注册时引导填写偏好问卷
- 初期采用"热门+多样性"策略
- 利用微信社交数据(如地区、年龄)
def cold_start_recommend(user): if not user.history: # 组合策略 return hot_movies()[:5] + diverse_movies()[:5]6.2 推荐多样性不足
现象:推荐结果过于集中在某些类型
改进方案:
- 引入Serendipity因子
def diversity_score(movie, user): genre_diff = 1 - cosine(user.genre_pref, movie.genres) return genre_diff * 0.7 + random.random() * 0.3 - 定期注入随机探索项
6.3 微信小程序审核问题
经验分享:
- 避免使用"推荐"等敏感词,改用"猜你喜欢"
- 用户数据收集需明确声明
- 分享功能不能强制要求用户授权
7. 项目总结与展望
这个项目从构思到实现历时4个月,期间最大的挑战是推荐算法的效果调优。通过AB测试发现,加入社交因素后推荐准确率提升了18%,但同时也增加了系统复杂度。
几个关键收获:
- 用户行为数据的质量比数量更重要
- 简单的算法组合往往比复杂模型更稳定
- 微信小程序的性能瓶颈主要在网络请求
未来改进方向:
- 引入实时流处理(如Flink)
- 尝试深度强化学习算法
- 增加跨平台支持(如H5版本)
这个项目让我深刻体会到,一个好的推荐系统不仅需要技术实力,更需要对人性的理解。当看到用户因为我们的推荐发现心仪电影时,那种成就感是无可替代的。