民宿预订这事,做过产品或者写过业务系统的朋友应该都清楚,它跟标品酒店完全是两套逻辑。酒店讲连锁标准化,用户要的是"大床房+早餐+停车位"这种确定性;民宿则是个性化极强的非标体验,同样一个城市,一栋老洋房和一间海景 loft 的受众完全不同。这就导致民宿平台最核心的能力不是"搜得到",而是"推得准"。所以当我决定做一个民宿相关的系统时,第一反应就是做推荐,而不是做传统的 CRUD 管理后台。
这套系统我用 Python 3.9 + Django 3.2 做主体工程,协同过滤推荐算法作为推荐引擎核心,配合 ECharts 做大数据可视化,并且留了大模型接口做推荐文案生成与意图理解。整套系统跑下来,既能给你一个能演示、能答辩的完整毕业设计,也能让真正想入行推荐系统的同学看懂从数据建模到算法落地的全过程。今天这篇文章不写那种"项目简介"式的流水账,我从需求拆解、表结构设计、算法实现、Django 工程代码、可视化看板到避坑经验,完整讲一遍。内容偏细,建议收藏了慢慢看。
1. 这个系统到底解决什么问题
1.1 民宿推荐和酒店推荐的差异
很多人一上来就套用电商推荐或者酒店推荐的做法,这是第一个坑。民宿的决策链路跟酒店有本质区别,主要体现在几个点上。第一,民宿的"非标属性"极强,同一个小区的两套房源,装修风格、房东服务、楼层采光都可能完全不同,所以物品层面很难用统一类目去归并;第二,用户对视觉信息极其敏感,图片质量直接决定点击率,这导致在协同过滤之外需要结合浏览行为做很多特征处理;第三,地理位置对决策的影响非常大,用户通常会限定一个商圈或者地铁站范围,然后在这个范围内比较房源,也就是说,地理过滤往往是推荐的前置条件。
基于这些差异,我设计这套系统时没有单纯依赖评分数据,而是把收藏、浏览时长、下单行为、价格区间偏好都纳入用户画像的构建过程中,并且在推荐排序前先做地理位置和可订状态的硬过滤。这样做的原因是,纯协同过滤在民宿场景下会有明显的稀疏性问题——用户一辈子可能就订几次民宿,评分数据非常少,如果只拿评分做推荐,基本等于裸奔。
1.2 为什么是 Python + Django + 协同过滤
技术选型这块,我见过太多人把简单问题复杂化了。有人上来就上 Spark、Hadoop,有人非要写微服务,结果毕设答辩的时候连部署都讲不清楚。我的原则是:用最成熟的技术栈解决核心问题,把精力花在算法效果和业务逻辑上。
Python 在这类项目里几乎是唯一解,因为后续的数据分析、模型实验、大模型接口调用全都可以在一个语言体系里完成,不用来回切换。Django 自带 ORM、Admin 后台、用户认证和模板引擎,能极大缩短工程开发时间,我在一周内就把用户端、管理端、接口层全部跑通了。协同过滤则是推荐系统里性价比最高的算法,它不需要标注数据,只用用户的历史行为矩阵就能计算出个性化推荐结果,而且通过余弦相似度、皮尔逊相关系数这些指标可以解释出"为什么推荐给你",答辩时非常有说服力。
提示:如果论文需要突出"大数据"属性,不要硬套大数据框架。你可以把数据采集、数据清洗、多维度统计分析、可视化报表这套完整链路做好,这在毕设层面已经足够扎实了。
这套系统的核心指标其实很明确:一是推荐准确度,能否准确预测用户对某个房源的偏好打分;二是召回覆盖率,能否从几千套房源中找出用户可能感兴趣的候选集合;三是列表多样性,避免推荐结果全是同一商圈同一种房型,否则会显得算法很蠢。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统的整体设计与数据建模
2.1 功能模块划分
我的系统按用户侧和管理侧拆分,用户端负责浏览、搜索、推荐信息流、收藏、下单、评价操作;管理端负责房源录入审核、订单管理、用户管理;中间层是推荐引擎,负责产出个性化推荐列表;最上层是数据可视化看板,把房源分布、价格区间、热度趋势等数据用图表呈现出来。
整体架构上,我没有把推荐算法直接塞进 Django View 里,那样代码一旦复杂就会失控。我单独建了一个 recommend 应用,里面放算法模块、缓存模块和定时任务。用户请求推荐列表的时候,View 只做参数解析和结果组装,真正的相似度计算、排序逻辑全部在 recommend 模块里完成。这个分层的好处是,就算你以后想改成 Redis 缓存热数据,或者把推荐引擎抽成独立服务,不用动 View 层代码。
code复制frontend (Django Template + ECharts)
backend (Django Apps: users / houses / orders / recommend / dashboard)
推荐引擎 (recommend: 协同过滤 + 热度兜底 + 大模型接口)
数据层 (MySQL 8.0 + Redis 缓存)
2.2 数据表结构怎么设计
数据表是这套系统的地基。我踩过一次坑,一开始图省事只建了三张表,用户表、房源表、订单表,结果写推荐算法的时候发现没有行为数据可用,还得回补收藏和评分记录。后来我把表结构重新整理成六张核心表,大家可以参考。
用户相关表中,除了 Djang 自带的 auth_user 之外,我单独做了一个 user_profile 表,用于存用户的偏好画像,包括常住城市、价格区间、偏好房型标签(如"复式""海景""浴缸"等)。房源 house 表是核心数据表,字段包括标题、城市、区域、地址经纬度、价格、房屋类型、入住人数、设施标签(JSON 格式)、评分、图片列表、状态(在售/下架)。行为数据方面,order 表记录下单,rating 表记录打分和评论,favorite 表记录收藏,这三张表共同构成推荐算法的输入。
推荐结果我建议单独建一张 recommendation_box 表,把离线算好的推荐结果按用户缓存进去,避免每次请求都实时跑全量计算。字段包括用户 ID、推荐房源 ID(JSON 数组)、策略类型(协同过滤/热度/混合)、生成时间。这样接口层只需要读一张表,响应速度能控制在 100ms 以内。
2.3 推荐流程中的数据流转
推荐流程可以用一句话概括:先圈定候选范围,再算相似度得分,最后人工规则排序。用户请求推荐后,系统先判断他有没有历史行为数据,如果有,走协同过滤流程;如果是新用户或者行为数据太少,走冷启动流程,按城市热度、好评率、价格适中规则推荐。
在这里我专门处理了地理位置的优先级。候选房源必须满足两个前置条件:第一是状态正常且可预订;第二是房源所在城市与用户当前定位一致。只有在候选集合满足这两个条件之后,推荐算法才有意义。很多同学实现协同过滤时全库跑相似度,推荐出一堆别的城市的房源,用户当然觉得不精准。
3. 协同过滤推荐算法的落地实现
3.1 用户-物品评分矩阵的构建
协同过滤的第一步,是把行为数据变成用户-物品评分矩阵。矩阵的行是用户,列是房源,每个元素表示用户对房源的偏好程度。
真实场景下评分是从多个维度合成的,不要只看 rating 表里的星星。我使用了一套加权方案:显式评分权重最高,占 60%;收藏行为权重其次,占 25%;浏览行为权重最小,占 15%。其中浏览行为还要做归一化处理,比如用户浏览某房源时长超过 60 秒标记为 1,超过 120 秒标记为 2,最多不超过 5 分。
最终合成公式为:
code复制pref_score = 0.6 * explicit_rating + 0.25 * favorite_score + 0.15 * view_score
其中 explicit_rating 如果没有评分,则取 0 不参与;设了多档衰减,避免高活跃用户的行为总是主导结果。为了方便后面的相似度计算,我构建 DataFrame 格式的稀疏矩阵,行索引是 user_id,列索引是 house_id,空位填 0。
3.2 基于用户的协同过滤(UserCF)
UserCF 的核心逻辑是"物以类聚、人以群分",找到跟你兴趣最相似的一批用户,然后把这些人喜欢的、你没见过的房源推荐给你。实现上分为三个步骤:计算用户相似度、找 K 个邻居、加权预测得分。
相似度计算我用最经典的余弦相似度公式。假设用户 A 和用户 B 的评分向量分别是 $(r_{A1}, r_{A2}, ..., r_{An})$ 和 $(r_{B1}, r_{B2}, ..., r_{Bn})$,那么余弦相似度定义为:
code复制cos(A, B) = Σ(r_Ai * r_Bi) / (sqrt(Σ r_Ai^2) * sqrt(Σ r_Bi^2))
我自己构造了一个例子来验证算法正确性。有三位用户对四套房源的评分矩阵如下:
| 用户 | 房源1 | 房源2 | 房源3 | 房源4 |
|---|---|---|---|---|
| A | 5 | 3 | 0 | 1 |
| B | 1 | 2 | 3 | 4 |
| C | 4 | 5 | 2 | 0 |
先算 A 和 B 的余弦相似度,分子是 $5×1 + 3×2 + 0×3 + 1×4 = 15$,分母是 $\sqrt{5^2+3^2+0^2+1^2} × \sqrt{1^2+2^2+3^2+4^2}$,约等于 5.916 × 5.477 = 32.4,最终相似度约 0.463。A 和 C 的相似度则是 $5×4 + 3×5 + 0×2 + 1×0 = 35$,分母约 5.916 × 6.708 = 39.7,最终约 0.882。所以 A 与 C 的兴趣更接近。
找到邻居后再预测 A 对房源 3 的评分,用加权平均公式:
code复制pred(A, 房源3) = avg_A + Σ[sim(A, N) * (r_N3 - avg_N)] / Σ|sim(A, N)|
每个用户自身的平均评分要先算出来,做归一化处理,避免有人习惯性打高分影响全体结果。预测出分数后对候选房源排序,去掉已订过的房源,取 TopN。
3.3 基于物品的协同过滤(ItemCF)
ItemCF 的逻辑是"喜欢某间房的人也会喜欢类似的房",更适合民宿这种用户需求相对明确、物品数量增长相对缓慢的场景。实现方式是把评分矩阵转置,把房源当成"用户",然后用同样的余弦相似度公式计算房源与房源的相似度矩阵。
在实际代码中,我维护了一张 item_similarity 表,字段是 house_id_a、house_id_b、similarity,用于存全量的房源相似度结果。离线任务在每天凌晨跑一遍,新产生的行为数据不做全量重算,只增量更新相关房源的相似度。这样既保证算法效果,又避免推荐接口响应过慢。
在相似度计算时,我对房源的属性相似度和行为相似度做了融合。属性相似度来自房源标签,比如"带露台""近地铁""允许宠物"这些标签重合度越高,属性越相似;行为相似度来自用户对两个房源的同时偏好。最终相似度取两者加权值,属性相似度权重 0.3,行为相似度权重 0.7。如果没有足够行为数据,就用属性相似度兜底。这段代码我直接写成函数,便于复用:
python复制def get_similar_houses(house_id, top_n=10):
# 读取离线算好的相似度矩阵
sim_df = similarity_manager.get_matrix()
if house_id not in sim_df.index:
return []
scores = sim_df.loc[house_id].drop(labels=[house_id]).sort_values(ascending=False)
return scores.head(top_n).to_dict()
3.4 混合推荐策略与冷启动兜底
只用任何一种协同过滤都有明显短板,所以我的推荐引擎最终采用加权混合策略。如果用户有较丰富的浏览历史,UserCF 和 ItemCF 分别给出 TopN 列表,然后按 6:4 的权重合并排序。如果用户历史行为稀疏(行为次数少于 5 次),就采用热度兜底策略:以房源综合热度排序去推荐。
综合热度也有一些计算公式,我用的是一套衰减模型:
code复制hot_score = (0.4 * 曝光量 + 0.3 * 收藏量 + 0.3 * 订单量) / pow(2, 房源上架天数 / 60)
加入时间衰减是因为民宿市场变化很快,上架很久的老房源评分再高,也不如下架后新上架的房源更值得推荐。新用户没有任何行为数据时,系统直接按目标城市的热度排行推荐,同时在前端标注"热门推荐"文案,掩饰算法还不了解你的事实。这种做法在工业界叫冷启动策略,答辩时老师问起来可以展开讲。
注意:冷启动阶段千万不要什么都不推荐,宁可推荐得平庸一点,也不要让用户面对空白页。一个空页面会让用户彻底失去探索兴趣,这在产品上比推荐偏差严重得多。
4. Django 工程实现与核心代码拆解
4.1 项目结构和环境准备
项目整体结构如下,清晰到可以当模板用:
code复制mybnb/
├── manage.py
├── config/ # 主配置模块
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── apps/
│ ├── users/ # 用户管理
│ ├── houses/ # 房源管理
│ ├── orders/ # 订单管理
│ ├── recommend/ # 推荐引擎
│ └── dashboard/ # 数据可视化
├── static/
├── templates/
└── scripts/
├── offline_compute.py # 离线任务:相似度矩阵/推荐结果
└── import_data.py # 数据导入脚本
环境这块建议把 Python 版本锁定在 3.9 或者 3.10,Django 用 3.2 LTS 版本,MySQL 用 8.0,Redis 作为缓存。为什么不用 Django 4.x 或者 5.x?因为很多第三方库和网上现成解决方案还是基于 3.2 写的,毕业设计求稳,版本老一点反而省心。安装命令我给一个常用集合:
bash复制pip install django==3.2.20 mysqlclient redis pandas numpy scikit-learn pyecharts
这里 mysqlclient 在 Windows 上安装可能会报错,建议直接下载对应 Python 版本的 whl 文件安装。pandas、numpy 做矩阵计算,scikit-learn 主要用于计算余弦相似度或者评估推荐结果的准确率,也可以自己写相似度函数。
4.2 models.py 的数据表定义
核心的数据表定义我在 models.py 里写好,然后让 Django 的 makemigrations 生成迁移文件建表。这里有个经验:JSONField 是 Django 3.2 以后内置支持的,把房源的设施标签、推荐结果列表都存成 JSON,能避免做多余的关联表,代码会简洁很多。
python复制class House(models.Model):
title = models.CharField(max_length=255, verbose_name="房源标题")
city = models.CharField(max_length=64, verbose_name="城市")
district = models.CharField(max_length=64, verbose_name="区域")
address = models.CharField(max_length=255, verbose_name="详细地址")
lat = models.FloatField(default=0.0)
lng = models.FloatField(default=0.0)
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="每晚价格")
house_type = models.CharField(max_length=32, verbose_name="房型")
tags = models.JSONField(default=list, verbose_name="设施标签")
score = models.FloatField(default=0.0, verbose_name="综合评分")
is_active = models.BooleanField(default=True, verbose_name="是否在售")
class Meta:
db_table = "house"
user_profile 表通过 OneToOne 关联 Django 自带的 auth_user,这样既保留了 Django 的用户认证体系,又扩展了画像字段。画像的更新策略是异步的:用户每次有搜索、收藏、下单动作,都会触发一次画像更新,把所有行为汇聚成偏好标签。
4.3 推荐服务模块的实现
推荐模块是整个系统的核心,我拆成两个文件:cf.py 存协同过滤核心算法,service.py 存面向业务调用的推荐服务。下面这段代码实现用户相似度的计算与 TopN 推荐,你可以直接拿去改:
python复制import numpy as np
from scipy.spatial.distance import cosine
def user_cf_recommend(user_id, rating_matrix, user_neighbors=10, top_n=20):
if user_id not in rating_matrix.index:
return []
current = rating_matrix.loc[user_id].values.astype(float)
sims = {}
for other_id in rating_matrix.index:
if other_id == user_id:
continue
other = rating_matrix.loc[other_id].values.astype(float)
# 跳过完全没有共同评分的用户
common = (current > 0) & (other > 0)
if np.sum(common) == 0:
continue
sims[other_id] = 1 - cosine(current, other)
top_neighbors = sorted(sims.items(), key=lambda x: x[1], reverse=True)[:user_neighbors]
if not top_neighbors:
return []
# 预测未评过分的房源
scores = {}
col_names = rating_matrix.columns
for i, house_id in enumerate(col_names):
if current[i] > 0:
continue
total_sim = 0.0
total_score = 0.0
for neighbor_id, sim_val in top_neighbors:
neighbor_score = rating_matrix.loc[neighbor_id, house_id]
if neighbor_score > 0:
total_sim += sim_val
total_score += sim_val * neighbor_score
if total_sim > 0:
scores[house_id] = total_score / total_sim
top_items = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_n]
return [house_id for house_id, _ in top_items]
这段代码关键点是:对每个没有评过分的目标房源,只在邻居中有过评分的那些里做加权平均;邻居相似度为负值的会被过滤掉(余弦距离转化时保证相似度非负)。我把每次推荐结果缓存起来,用户第一次请求时算一次,后续 24 小时内直接读缓存,性能上没有什么压力。
4.4 视图函数与接口设计
前端展示我用 Django Template + Vue 3 的简单组合,模板负责页面骨架,Vue 负责推荐列表的渲染和交互。后端 View 只需要返回 JSON 数据,由前端通过 axios 请求接口。下面的代码返回推荐列表:
python复制from django.http import JsonResponse
from django.views.decorators.http import require_GET
@require_GET
def recommend_list(request):
user_id = request.user.id
city = request.GET.get("city", "北京")
limit = int(request.GET.get("limit", 10))
service = RecommendService()
houses = service.get_recommendation(user_id, city, limit)
data = [
{
"id": h.id,
"title": h.title,
"price": float(h.price),
"rating": h.score,
"district": h.district,
"tags": h.tags,
"image": h.cover_url,
}
for h in houses
]
return JsonResponse({"code": 0, "data": data, "msg": "success"})
接口设计上我统一返回 {code, data, msg} 结构,前端判断 code 为 0 则正常展示。如果用户未登录,推荐接口照样返回热度推荐,只是不记录个性化行为,这样做的好处是游客也能看到完整页面,不会因为登录拦截造成无效浏览。
4.5 可视化看板怎么呈现
数据可视化我用了 ECharts,主要展示四张图:第一张是中国地图,用散点图展示房源在不同城市的分布与热度;第二张是价格区间柱状图,展示 300 元以下、300-600、600-1000、1000 以上各区间房源数量;第三张是订单趋势折线图,展示最近 30 天的预订量变化;第四张是标签词云,展示用户搜索和收藏中最常出现的房源标签。
这些图的数据来源不是实时算的,而是每天凌晨跑一个统计任务,把结果写入 dashboard_summary 表。前端页面只需要定时请求一次聚合数据接口,渲染出图表即可。可视化这一块,做毕设答辩时特别加分,因为它能把"大数据分析"这个抽象概念变成评委看得见的成果。我建议至少把城市热度、价格分布、预订趋势、用户画像画出来。
5. 大模型在推荐系统中的拓展应用
5.1 推荐理由的自然语言生成
之前说过,推荐系统最怕"黑盒"——用户不知道为什么被推荐这个房源,信任度就会下降。传统的协同过滤只能输出相似度数字,但无法解释给用户。这里我引入大模型接口,把推荐结果变成一句话推荐理由,极大提升体验。
实现方式很简单。协同过滤算出 TopN 房源后,把用户画像关键词、目标房源特点交给大模型:
code复制请根据以下信息生成一句不超过50字的推荐理由:
用户偏好:情侣出游、海景、预算600元以内
候选房源:青岛金沙滩海景Loft,688元/晚,有浴缸,可看日出
大模型输出类似"预算内体验感拉满的海景 Loft,清晨睁眼就是日出,情侣出行首选。",再拼接到推荐卡片下方。这部分我用的是模拟接口实现,不会让调用阻塞推荐主流程,大模型接口异常时自动降级为默认文案"猜你喜欢",保证整体可用性。
5.2 基于意图理解的智能搜索
第二个大模型应用点是民宿搜索的自然语言理解。传统搜索是输入"青岛 海景 民宿"这样结构化关键词,而用户真实输入往往是"想找个安静点又能看海的房子,最好带浴缸"。这种表达很难用等于查询匹配。
我的方案是让大模型做意图解析,把自然语言转化为结构化筛选条件,输出 JSON:
json复制{
"city": "青岛",
"features": ["海景", "浴缸", "安静"],
"price_max": null,
"house_type": null
}
后端拿到这份 JSON,转成 Django ORM 的过滤条件,再从数据库里检索候选房源,最后结合用户历史行为做重排序。这个方案本质上就是把大模型当成语义理解组件,不改变推荐算法的核心链路,但能把用户的长尾需求接进来。
5.3 多目标平衡与细节取舍
加了这些扩展后我要提醒你一个问题:推荐系统不能只盯准确率。真实场景里需要同时考虑平台营收、用户体验、供应平稳,但毕设阶段你只需要把握三个目标——准确率、覆盖率、可解释性。大模型主要服务于可解释性和搜索体验,协同过滤负责准确率和覆盖率的优化,两者各司其职。
大模型接口的调用要注意超时和限流。我在 Django 里用 requests 去调用,设置了 5 秒超时,失败则跳过文案生成。还封装了一个 LLMClient 类,方便后续切换不同模型服务。这部分代码量不大,但能体现工程素养,在论文里可以单独写一小节讲"大模型与推荐系统的结合"。
提示:答辩时如果老师问"大模型是怎么训练的",不要含糊。你的系统用的是开箱即用的推理服务,核心价值在于提示词设计和结果降级策略,把这点讲清楚就足够了。
6. 常见问题与避坑指南
6.1 环境与部署问题
很多同学卡在第一步 pytz.utm 或者 mysqlclient 编译失败这类环境问题上。这里我给一份排查表,都是我实测验证过的:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| pip install mysqlclient 报错 | Windows 缺少 C 编译器 | 下载对应 Python 版本的 mysqlclient whl 安装 |
| Django 启动时检测到 timezone 警告 | 版本兼容问题 | 在 INSTALLED_APPS 中明确配置 'pytz' |
| collectstatic 后样式丢失 | DEBUG=False 未配置静态文件 | 用 WhiteNoise 中间件或 nginx 托管静态文件 |
| Redis 连接 ConnectionError | Redis 服务未启动 | 打开 Redis-server,并检查密码配置 |
部署方面我建议用 gunicorn + nginx 上线到一台 2C4G 的云服务器上,Django 配置静态文件压缩和数据库连接池。如果只在本机演示,那直接 runserver 也够用,但论文里最好写清楚生产部署方案,至少有这个架构意识。
6.2 算法层面的典型问题
冷启动问题排名第一。新用户没有任何行为记录,协同过滤算不出相似度。我的解法是两级兜底:先看用户是否填过偏好画像,如果填过,用画像标签匹配房源属性;没填过就直接走城市热度推荐。另外新用户注册时会引导选择感兴趣的民宿类型,这些数据正好服务于冷启动推荐。
稀疏性问题排名第二。民宿订单量相比电商来说小很多,用户-物品矩阵中 95% 以上的位置都是 0。如果直接算余弦相似度,会出现大量用户之间没有共同评分的情况。我在算法里加了"至少存在一个共同评分项"的过滤条件,再配合皮尔逊相关系数的均值中心化处理,把缺失值影响降到最低。
相似度结果全为 0 的问题也遇到过。排查后发现自己取的评分矩阵没有做数据类型转换,评分项全成了字符串,0 和 0 之间比较永远相等,导致计算全部失效。这提醒我:用 pandas 处理数据,第一件事就是确认 dtype 是 float 而不是 object。
6.3 数据层面的问题
数据集是整个项目的命脉。网上能找到的民宿公开数据集很少,很多经典推荐数据集是电影或者商品领域的,直接用会造成领域不匹配。我的做法是结合真实平台公开页面的字段规范(不做爬取,只做字段设计),自己生成了一套模拟民宿数据,包含 800 个用户、3000 套房源、8000 条行为记录。生成的关键是让数据分布足够贴近现实:价格服从对数正态分布、城市热度差异大、用户偏好有一定的社区聚集性。
数据导入用独立的脚本完成,脚本里处理了中文编码问题,MySQL 连接字符串中加上 charset='utf8mb4',避免写入中文时出现乱码。这条经验很细节,但漏掉了会让你在导入数据阶段浪费半天时间。
6.4 性能优化建议
推荐接口的实时计算一定不要发生在请求链路里。我的方案是离线计算 + 在线读取。每天凌晨两点,定时任务全量跑一遍相似度矩阵和 TopN 推荐结果,写入 MySQL,白天用户请求时直接读缓存。这个方案简单可靠,哪怕数据量翻十倍也能扛住。
在 Django 层面还做了一些常规优化:ORM 查询用 select_related 和 only("id", "title", "price") 控制字段返回;列表接口开启分页,每页最多 20 条;热门房源的详细数据用 Redis 的字符串类型缓存,key 设置为 house:{id},过期时间设在 6 小时,房源信息修改时主动清掉对应缓存。
7. 写在最后:一点个人体会
做完这套系统,我最深的感受是:推荐系统的难点从来不在算法有多深,而在于你到底有没有把用户的需求抽象对。协同过滤本身原理并不复杂,几十行代码就能实现,但只有当数据表设计合理、行为权重设置得当、特征处理充分时,它才真正有效果。
另外一个实用体会是:像 Django 这种成熟框架,真正拉开开发效率差距的,是你对目录结构、模块职责划分的理解。千万别把所有逻辑堆在 views.py 里,那样子代码到后期根本没法维护。我采用 app 分模块、算法层独立、缓存层薄封装的做法,整个项目跑下来代码量控制在一万行以内,但是逻辑非常清爽。
最后留个扩展方向。如果你想在这个项目基础上继续加亮点,可以考虑把单机推荐改成分布式缓存架构,或者把离线协同过滤升级成在线实时召回+排序的两阶段推荐架构,再配合大模型的语义理解能力,就完全是一个工业级民宿推荐系统的雏形了。
