1. 项目背景与核心价值
每次打开外卖软件面对上百家餐厅时,选择困难症就会发作。这个推荐系统要解决的就是这个痛点——通过分析用户历史订单和相似用户的选择,自动推荐最可能符合口味的美食。不同于简单按销量或评分排序,协同过滤算法能捕捉到"喜欢川菜的人通常也爱湘菜"这类隐藏关联。
我在开发这套系统时发现,餐饮推荐有三大特殊性:1)用户口味差异极大(有人无辣不欢,有人一点辣不沾)2)消费频次高(每周可能点5-10次外卖)3)存在明显时段特征(早餐爱豆浆油条,夜宵偏好烧烤)。这些特点让传统推荐策略效果大打折扣。
2. 系统架构设计
2.1 数据层处理
原始订单数据需要转化为用户-菜品评分矩阵。这里有个关键技巧:不能简单用点餐次数作为评分。我们设计了加权公式:
code复制评分 = 点餐次数 × 0.6 + 重复点餐间隔系数 × 0.4
间隔系数=1/(最近两次点餐间隔天数),这样上周连续点3次的酸菜鱼会比半年前点过5次的水煮鱼权重更高。
2.2 相似度计算优化
余弦相似度计算时遇到稀疏矩阵问题——用户平均只尝试过0.3%的菜品。我们采用SVD矩阵分解降维,把5000维的菜品空间压缩到150维,不仅提升计算效率,还发现了"早餐党"、"健身餐族"等潜在用户群体。
实际测试发现,当用户历史订单少于15单时推荐准确率会骤降。我们的解决方案是:新用户先用基于内容的推荐(菜品标签匹配),积累足够数据后再切换协同过滤。
3. 核心算法实现
3.1 用户相似度计算
核心代码片段(Python):
python复制from scipy.spatial.distance import cosine
def user_similarity(user1, user2):
# 获取共同评分菜品索引
common_items = np.intersect1d(
np.where(~np.isnan(user1)),
np.where(~np.isnan(user2))
)
if len(common_items) < 5: # 共同评价过至少5道菜
return 0
vec1 = user1[common_items]
vec2 = user2[common_items]
return 1 - cosine(vec1, vec2)
3.2 推荐生成策略
采用混合推荐策略:
- 找出Top20相似用户
- 聚合他们评价≥4星且目标用户未点过的菜品
- 按公式计算推荐分:
code复制推荐分 = 相似度 × 评分 × 时效系数
时效系数=1/(菜品最近被点日期距今天数+1)
4. 工程化落地难点
4.1 实时性挑战
最初用离线批处理导致新用户要等6小时才能获得推荐。后来改造为:
- 用户画像实时更新服务
- 相似度预计算+局部更新
- 菜品特征向量缓存
使95%的推荐响应时间控制在300ms内。
4.2 冷启动解决方案
我们构建了菜品知识图谱,包含:
- 口味(辣/甜/酸度)
- 烹饪方式(煎炸/清蒸等)
- 食材构成
- 营养指标
新用户注册时通过3道测试题(如"你能接受的最大辣度")建立初始画像。
5. 效果验证与调优
5.1 AB测试设计
将用户随机分为三组:
- 对照组:按销量排序
- 实验组1:基础协同过滤
- 实验组2:我们的优化算法
关键指标对比:
| 指标 | 对照组 | 实验组1 | 实验组2 |
|---|---|---|---|
| 点击转化率 | 12.3% | 18.7% | 23.5% |
| 下单转化率 | 6.8% | 9.2% | 11.9% |
| 平均客单价 | ¥38.5 | ¥42.6 | ¥45.2 |
5.2 bad case分析
发现健身用户偶尔会收到炸鸡推荐。排查发现:
- 部分用户工作日吃健身餐,周末"放纵餐"
- 解决方案:引入时间上下文特征,区分工作日/周末推荐策略
6. 部署架构演进
6.1 初期单机方案
plaintext复制[Nginx] -> [Flask API] -> [MySQL]
-> [离线Spark作业]
问题:用户增长后MySQL查询成瓶颈
6.2 微服务化改造
plaintext复制[API Gateway]
|- [用户画像服务] (Redis)
|- [推荐计算服务] (Faiss向量检索)
|- [菜品特征服务] (MongoDB)
|- [日志收集服务] (Kafka+ES)
关键优化:
- 用户画像改用Redis,读取速度从120ms降到8ms
- 相似度计算改用Faiss,TopK查询提速15倍
- 引入分级缓存:本地缓存+Redis集群
7. 业务思考延伸
这套系统后来衍生出两个重要功能:
- 备餐预警:当某菜品被大量相似用户突然差评时(可能换了厨师),自动触发品控检查
- 智能套餐:分析"A用户常点B菜+C饮料"的组合模式,生成推荐套餐
有个反直觉的发现:推荐系统上线后,最受欢迎的菜品类目数量反而增加了37%。这说明好的推荐不是让用户局限在已知范围,而是帮他们更高效地发现新选择。