零食电商平台面临的最大痛点之一是如何在海量商品中帮助用户快速发现符合个人偏好的产品。传统分类浏览和简单销量排序已经无法满足个性化需求,这正是推荐系统大显身手的场景。这个项目采用协同过滤算法作为核心推荐引擎,配合Django后端与Vue3前端的现代化技术栈,构建了一个能自主学习用户口味偏好的智能零食商城。
协同过滤算法的魅力在于它不需要复杂的商品特征分析,仅通过用户行为数据(浏览、购买、评分)就能挖掘出"相似用户喜欢相似商品"的潜在规律。比如当用户A和用户B都对麻辣味零食表现出相同偏好时,系统就会自动将B喜欢的其他辣味食品推荐给A。这种"物以类聚,人以群分"的推荐逻辑特别适合零食这种强偏好型商品。
注意:实际部署时需要平衡推荐新颖性和准确性,避免陷入"信息茧房"。好的推荐系统应该既有惊喜感又保持相关性。
系统采用经典的前后端分离架构:
python复制# 典型接口示例
@api_view(['GET'])
def recommend(request):
user_id = request.GET.get('uid')
# 从Redis获取实时行为数据
user_actions = cache.get(f'user:{user_id}:actions')
# 调用推荐算法
rec_items = recommend_engine(user_actions)
return Response(rec_items)
项目实现了两种经典协同过滤变体:
基于用户(UserCF):适合用户量小于商品量的场景
基于物品(ItemCF):适合商品更新不频繁的场景
python复制# 相似度计算示例(皮尔逊相关系数)
def pearson_sim(user1, user2):
common_items = set(user1.items) & set(user2.items)
n = len(common_items)
if n == 0: return 0
sum1 = sum(user1[i] for i in common_items)
sum2 = sum(user2[i] for i in common_items)
sum1Sq = sum(pow(user1[i],2) for i in common_items)
sum2Sq = sum(pow(user2[i],2) for i in common_items)
pSum = sum(user1[i]*user2[i] for i in common_items)
num = pSum - (sum1*sum2/n)
den = sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
return num/den if den !=0 else 0
实操心得:零食类目的用户偏好往往呈现"短时集中"特点,建议对最近7天的行为数据赋予更高权重。
新用户和新商品面临的冷启动问题通过以下策略缓解:
python复制def cold_start(user):
if not user.history:
# 返回热门商品+随机采样
hot_items = cache.get('hot_items')
random_items = random.sample(all_items, 10)
return hot_items[:5] + random_items
else:
return normal_recommend(user)
传统协同过滤的批量计算模式无法满足实时性要求,项目采用:
python复制def hybrid_recommend(user):
cf_items = user_cf(user) # 协同过滤结果
realtime_items = realtime_engine(user.last_click) # 实时推荐
# 加权融合(可动态调整)
return {
'recommend': cf_items[:3] + realtime_items[:2],
'reason': {
'cf': '与你口味相似的用户也喜欢',
'realtime': '根据最近浏览推荐'
}
}
Vue3的组合式API特别适合构建动态推荐界面:
vue复制<script setup>
import { ref, onMounted } from 'vue'
const recList = ref([])
const loading = ref(true)
onMounted(async () => {
const res = await fetch(`/api/recommend?uid=${user.id}`)
recList.value = await res.json()
loading.value = false
})
</script>
<template>
<van-skeleton v-if="loading" row="3" />
<div v-else>
<h3>猜你喜欢</h3>
<van-grid :column-num="3">
<van-grid-item
v-for="item in recList"
:key="item.id"
:text="item.name"
:icon="item.image"
/>
</van-grid>
</div>
</template>
协同过滤最大的性能瓶颈在于相似度计算,优化方案包括:
python复制# 使用Faiss加速(需要安装faiss-cpu)
import faiss
class FaissKNN:
def __init__(self, vectors):
self.dimension = vectors.shape[1]
self.index = faiss.IndexFlatL2(self.dimension)
self.index.add(vectors)
def query(self, vector, k=5):
distances, indices = self.index.search(vector, k)
return indices[0]
推荐结果采用多级缓存:
重要提示:缓存键设计要包含用户分段标识,如"rec:vip:{user_id}"和"rec:normal:{user_id}",便于差异化策略管理。
建立完整的评估体系:
python复制def evaluate(recommends, tests):
hit = len(set(recommends) & set(tests))
precision = hit / len(recommends)
recall = hit / len(tests)
f1 = 2 * precision * recall / (precision + recall)
return {'precision': precision, 'recall': recall, 'f1': f1}
通过AB测试持续优化:
sql复制-- 实验结果分析SQL示例
SELECT
group_id,
COUNT(DISTINCT user_id) as uv,
SUM(click) / COUNT(*) as ctr,
SUM(cart) / COUNT(*) as cart_rate
FROM ab_test_logs
WHERE dt = '2023-07-15'
GROUP BY group_id
使用Docker Compose编排服务:
yaml复制version: '3'
services:
web:
build: ./django_app
ports: ["8000:8000"]
depends_on:
- redis
- mysql
redis:
image: redis:alpine
volumes:
- redis_data:/data
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- mysql_data:/var/lib/mysql
volumes:
redis_data:
mysql_data:
推荐系统的日志需要特殊处理:
python复制# 结构化日志示例
import structlog
logger = structlog.get_logger()
def recommend(request):
start = time.time()
# ...推荐逻辑...
duration = time.time() - start
logger.info(
"recommend.completed",
user_id=user_id,
item_count=len(result),
duration_ms=round(duration*1000),
from_cache=from_cache
)
return result
实际部署中发现,零食推荐与生鲜电商最大的不同在于用户更愿意尝试新品。因此我们在算法中适当提高了新颖性指标的权重,通过定期引入随机探索机制,使系统保持约15%的新品曝光率。这个数值经过多次AB测试确定,能在商业目标和用户体验间取得较好平衡。