1. 项目概述与核心需求
这个基于Django的景区门票预订系统项目,核心目标是通过智能推荐算法提升用户购票体验和景区营销效果。我在实际开发中发现,传统票务系统最大的痛点在于"信息过载"——用户面对上百个景区选项时往往无从下手。而我们的系统通过分析用户历史行为数据,能够主动推荐符合其偏好的景区,将转化率提升了30%以上。
系统采用Python+Django全栈开发,主要包含三大核心模块:
- 基础票务功能(用户管理、景区展示、订单处理)
- 智能推荐引擎(协同过滤+内容过滤混合算法)
- 运营数据分析看板
特别值得一提的是推荐算法部分,我们不仅实现了经典的协同过滤,还创新性地加入了地理位置权重因子。测试数据显示,当推荐结果中包含用户当前位置50公里内的景区时,下单率会显著提高。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体架构方案
系统采用经典的MTV模式,但针对推荐场景做了特殊优化:
code复制前端层(Vue.js+Bootstrap)
↑
API层(Django REST Framework)
↑
业务逻辑层(推荐算法+订单处理)
↑
数据层(MySQL+Redis)
↑
基础设施(Nginx+Gunicorn)
这个架构有几点关键设计考量:
- 前后端分离:便于多端适配和API复用
- 双缓存策略:Redis既缓存热点数据,又存储实时推荐结果
- 异步任务队列:用Celery处理耗时的推荐计算
2.2 数据库设计要点
在模型定义时,我特别注重了行为数据的采集粒度。比如UserBehavior模型不仅记录浏览行为,还捕获了停留时长这个重要指标:
python复制class UserBehavior(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
spot = models.ForeignKey(ScenicSpot, on_delete=models.CASCADE)
behavior_type = models.CharField(max_length=20) # view/collect/rate
duration = models.FloatField(null=True) # 页面停留秒数
intensity = models.FloatField(default=1.0) # 行为强度系数
经验提示:duration字段后来被证明非常有用 - 停留超过30秒的浏览记录,在推荐算法中的权重是普通浏览的3倍
3. 推荐算法实现细节
3.1 混合推荐策略
我们最终采用的算法组合是:
- 60% 物品协同过滤(ItemCF)
- 30% 内容相似度(基于标签)
- 10% 地理位置因子
python复制def hybrid_recommend(user):
# 获取基础推荐
itemcf_rec = itemcf_recommend(user)
content_rec = content_based_recommend(user)
geo_rec = geo_recommend(user)
# 混合加权
combined = {}
for rec, weight in [(itemcf_rec,0.6), (content_rec,0.3), (geo_rec,0.1)]:
for spot, score in rec.items():
combined[spot] = combined.get(spot, 0) + score * weight
# 返回Top10
return sorted(combined.items(), key=lambda x: -x[1])[:10]
3.2 冷启动解决方案
对于新用户,我们设计了三级降级策略:
- 首选:手机定位获取周边景区
- 备选:当天热门景区排行
- 保底:人工精选的"城市必玩榜单"
实测这套方案使新用户的首推点击率从12%提升到了28%。
4. 关键功能实现
4.1 实时推荐接口
采用DRF开发的推荐API有两个优化点值得分享:
python复制class RecommendationAPI(APIView):
@method_decorator(cache_page(60*15)) # 缓存15分钟
def get(self, request):
user = request.user
if not user.is_authenticated:
return self._handle_anonymous(request)
# 实时计算版本
spots = recommend_spots(user.id)
# 加入商业逻辑:优先推荐有促销的景区
spots = self._apply_business_rules(spots)
serializer = ScenicSpotSerializer(spots, many=True)
return Response(serializer.data)
踩坑记录:最初没有加缓存,导致高峰期CPU负载过高。后来改为"预计算+缓存"模式,QPS从50提升到了300+
4.2 行为数据埋点
在前端用JavaScript实现了细粒度的行为采集:
javascript复制// 景区详情页埋点
document.addEventListener('DOMContentLoaded', () => {
let startTime = Date.now();
window.addEventListener('beforeunload', () => {
const duration = (Date.now() - startTime) / 1000;
navigator.sendBeacon('/api/behavior', JSON.stringify({
spot_id: {{ spot.id }},
duration: duration
}));
});
});
5. 性能优化实战
5.1 推荐结果缓存
Redis的缓存设计采用了分层策略:
- 第一层:用户个性化推荐(TTL 15分钟)
- 第二层:热门景区列表(TTL 1小时)
- 第三层:基础数据缓存(TTL 24小时)
python复制def get_recommendation(user_id):
cache_key = f"rec:{user_id}"
cached = redis.get(cache_key)
if cached:
return json.loads(cached)
# 缓存未命中时重新计算
result = calculate_recommendation(user_id)
redis.setex(cache_key, 900, json.dumps(result)) # 15分钟过期
return result
5.2 数据库查询优化
发现景区列表页的SQL查询存在N+1问题后,我们通过以下方式优化:
python复制# 优化前(每次循环都查数据库)
spots = ScenicSpot.objects.all()
for spot in spots:
print(spot.tags.all()) # 每次循环都产生查询
# 优化后(预加载关联数据)
spots = ScenicSpot.objects.prefetch_related('tags').all()
这个改动使列表页加载时间从1200ms降到了300ms。
6. 部署与监控方案
6.1 生产环境部署
我们的部署架构包含以下关键组件:
- Web服务器:Nginx(静态文件+负载均衡)
- 应用服务器:Gunicorn(4 worker进程)
- 任务队列:Celery + Redis
- 监控:Prometheus + Grafana
部署时特别注意了Gunicorn的配置优化:
bash复制gunicorn core.wsgi:application \
--workers=4 \
--threads=2 \
--bind=0.0.0.0:8000 \
--timeout=120 \
--max-requests=1000
6.2 推荐算法监控
在Grafana中建立了专门的推荐看板,监控以下指标:
- 推荐点击率(CTR)
- 算法耗时百分位(P50/P95/P99)
- 冷启动覆盖率
- 缓存命中率
7. 踩坑与经验总结
7.1 算法效果波动问题
上线初期发现推荐效果时好时坏,排查后发现是因为:
- 行为数据不足时,相似度计算不准确
- 节假日期间用户行为模式突变
解决方案:
- 增加了基于时间窗口的衰减因子
- 对特殊日期配置独立的推荐策略
7.2 并发下单冲突
遇到过景区库存超卖的问题,最终通过以下方案解决:
python复制@transaction.atomic
def create_order(user, spot, tickets):
# 使用select_for_update锁定记录
spot = ScenicSpot.objects.select_for_update().get(pk=spot.id)
if spot.available_tickets < tickets:
raise ValueError("库存不足")
spot.available_tickets -= tickets
spot.save()
# 创建订单...
8. 扩展优化方向
根据实际运营数据,下一步计划重点优化:
- 实时推荐:用Kafka处理用户实时行为事件
- 多目标优化:平衡景区收益和用户体验
- 可视化配置:让运营人员能调整算法权重
一个有趣的发现:当推荐结果中包含1个"小众精品"景区时,整体点击率会提升5-8%。这启发我们在算法中加入了惊喜度因子。
