基于Java与协同过滤的宠物之家推荐系统设计与实现

发布时间:2026/10/9 5:54:30
基于Java与协同过滤的宠物之家推荐系统设计与实现
每年到毕业季总有一批学弟学妹拿着差不多的题目来找我基于智能推荐的宠物之家网站设计与实现。这个题在计算机本科毕设里属于典型的稳妥又出彩组合——说稳妥是因为 Java 后端加 Web 开发的技术路线非常成熟Spring Boot、MyBatis、MySQL 这套组合在就业市场上仍然是绝对主流资料多、报错好查说出彩是因为智能推荐四个字天然就带来创新感做出来是个完整系统写论文也有核心亮点又不至于难到本科生推不动。适合刚做完课程设计、想完整走一遍项目研发流程的同学也适合那些希望在简历上写一个带推荐算法项目的求职者。这篇文章我把这个题目从选题到答辩完整拆一遍技术选型、推荐算法落地、数据库设计、常见坑全部按实操经验来写。1. 项目定位与核心需求拆解1.1 为什么选型选中了Java 智能推荐 宠物先说选题逻辑。计算机毕设最重要的不是题目多炫而是你能撑得住、讲得清、做得完。Java 方向在这一点上性价比极高国内高校的 Java Web 课程体系最完整Spring Boot 生态的文档和社区案例多到看不完遇到奇怪的问题基本一搜就有答案。对毕设这种时间紧、没人带、还要独立跑通全流程的项目来说这本身就是巨大的隐性优势。另外Java 岗位的需求量一直稳定项目做完写进简历面试官从 Spring 问到数据库、从接口设计问到算法细节你都有真实代码可以讲比背八股文有说服力得多。再看智能推荐这个标签。纯增删改查的宠物网站毕设太常见了每年答辩台上全是雷同的页面评委早就看麻了。加上推荐系统之后项目的性质完全不一样它从管理系统升级成了服务平台论文里可以写用户行为建模、相似度计算、推荐策略设计工作量和技术含金量同时上来。最关键的是这个创新点可深可浅——基础版本做一个基于物品的协同过滤就够撑起全局进阶版本再加混合召回和冷启动处理完全看你的时间和能力。最后说宠物场景为什么合适。宠物之家这类垂直信息平台天然就有推荐系统的用武之地。用户浏览过柯基犬、收藏过无谷猫粮、咨询过猫咪绝育这些行为都能转化成推荐模型的输入。相比图书、电影这些经典推荐数据集宠物信息更贴近日常生活演示的时候评委一看就懂不需要额外解释业务背景。而且宠物信息更新频率低、物品数量相对可控对推荐算法的实现难度也是友好的。1.2 角色划分与核心业务流程一个完整的宠物之家平台我建议做成三类角色别贪多但也不能太少否则系统会显得单薄。普通用户注册登录、浏览宠物、搜索筛选、收藏点赞、在线咨询、提交领养申请。这是推荐系统的主要服务对象。宠物提供方宠物店/救助站/个人送养发布宠物信息、上下架管理、回复咨询、处理领养申请。注意这类角色最好用商家/发布者统一身份不要和普通用户混在一个权限模型里。平台管理员用户管理、宠物信息审核、分类维护、数据统计、推荐参数配置。核心业务流程可以这样描述用户进入网站 → 浏览首页推荐位或主动搜索 → 点击宠物卡片查看详情 → 产生浏览、收藏、点赞、咨询等行为 → 系统记录这些行为并更新用户画像 → 下一次访问时推荐引擎根据历史行为生成个性化推荐 → 用户对推荐结果继续产生行为形成数据闭环。这个闭环要在需求分析阶段就画出来因为后面的数据库设计和推荐引擎实现全部围着它转。1.3 功能模块一张表看清我习惯在写代码前先把功能模块表列出来这样后端建表、前端做页面、论文写需求分析都能直接复用。模块名称核心功能涉及角色与推荐系统的关系用户管理注册、登录、个人资料、偏好标签设置全部偏好标签用于冷启动推荐宠物信息管理宠物发布、上下架、详情编辑商家、管理员推荐物品池的数据来源检索与分类关键词搜索、按品种/价格/年龄筛选用户解决主动找宠物的需求行为采集浏览、收藏、点赞、咨询记录用户推荐算法最核心的数据输入智能推荐首页个性化推荐、详情页相似推荐、热门榜用户系统核心亮点领养管理领养申请提交、审核、状态跟踪用户、管理员高意向行为可加权计入推荐分后台管理用户审核、宠物审核、数据统计、推荐参数配置管理员推荐策略可调控的后端入口表格里最能体现设计水平的是行为采集和智能推荐两个模块。很多同学做完前面那些 CRUD 就说系统完成了实际上推荐系统没数据、没算法整个题目的灵魂就丢了。行为采集必须在前端页面和后端接口两个层面同时做这件事我在第三章详细讲。2. 技术栈选型与系统架构设计2.1 后端技术栈怎么选才不给自己挖坑后端我推荐一套保守但完全够用的组合JDK 8 或 11 Spring Boot 2.7.x MyBatis-Plus 3.5.x MySQL 8.x Maven前端用 Thymeleaf 做服务端渲染Redis 做缓存层可选但不强制。逐一说理由。JDK 版本不用追新8 或 11 在企业里还有大量存量系统兼容性最好。Spring Boot 2.7.x 的生态最稳定网上搜到的教程、踩坑记录绝大多数都是这个版本遇到问题好解决Spring Boot 3.x 虽然新但要求 JDK 17部分老教程的配置写法会失效毕设没必要冒这个险。MyBatis-Plus 是我特别推荐选的它能在实体类上直接加注解生成建表语句自动生成单表 CRUD分页插件内置写代码效率比原生 MyBatis 高不少而且生成的代码结构清晰论文里也好描述。MySQL 8 是标配基本不用解释。Redis 这个点我要多说两句。推荐系统离不开缓存首页热门榜、TopN 推荐结果、宠物详情热点数据全放 Redis 里会大大提升响应速度。但如果你的机器上没装 Redis或者担心环境配置出问题完全可以用本地 ConcurrentHashMap Spring 定时任务顶替效果一样能演示。答辩时如果评委问你为什么不用 Redis你回答考虑到部署环境简单性选择轻量级本地缓存方案并通过接口抽象预留了升级 Redis 的扩展点这就是一个标准且得体的回答。前端用 Thymeleaf 我和很多同学说过毕设是单人项目服务端渲染页面可以少写大量前后端联调的代码页面和控制器的关系非常直接出了问题一眼就能定位。如果你前端基础特别好想上 Vue3 Element Plus当然也可以但意味着额外增加接口设计、跨域处理、前端构建这些工作量。求稳就选 Thymeleaf这个选择没有任何丢分的地方。2.2 推荐算法选型为什么首选 ItemCF 协同过滤推荐算法是整个项目的灵魂但很多同学一上来就懵基于内容的推荐、协同过滤、矩阵分解、深度学习到底选哪个我的建议非常明确首选基于物品的协同过滤ItemCF理由是这个算法最贴合宠物之家场景且实现难度适中。先讲原理。ItemCF 的核心思想是喜欢这个物品的用户也会喜欢与它相似的物品。在宠物之家场景里就是一大批用户同时浏览/收藏了柯基犬和柴犬系统就认为这两个宠物相似度很高当某个用户浏览过柯基犬就给他推荐柴犬。为什么不用基于用户的协同过滤UserCFUserCF 找的是和你兴趣相似的其他用户然后推荐那个用户喜欢的物品。它更适合新闻、短视频这类物品更新快、用户兴趣变化快的场景。而宠物之家是垂直平台宠物品种和商品信息更新速度慢用户对宠物的偏好相对稳定持久用 ItemCF 算出来的相似关系能稳定复用很长时间离线算好相似度矩阵后可以直接缓存在线召回非常快。和基于内容的推荐相比ItemCF 不需要人工维护宠物的属性标签它完全从用户行为中自动学习物品之间的相似关系既省人力效果往往还更意外惊喜——用户自己可能都没意识到柯基和柴犬有什么共同点系统却能通过行为数据发现它们经常一起被关注。这在论文里是很好的讨论素材。2.3 数据库设计表和字段怎么定才有推荐可算数据库设计直接决定推荐算法好不好实现。很多毕设把宠物表建得特别复杂却没给用户行为表留位置这是最要命的。我的核心表设计如下user 用户表id、username、password、nickname、avatar、preference_tags偏好标签JSON 数组或逗号分隔、create_time。偏好标签字段是冷启动推荐的关键注册时让用户选猫/狗/小型/大型等标签后面推荐系统才有初始依据。category 宠物分类表id、name、sort。猫、狗、小宠、水族之类结构简单但不能缺。pet 宠物信息表id、category_id、name、breed、age、sex、price、vaccine_status、description、cover_image、status0 下架 1 上架、view_count、create_time。view_count 浏览量字段不要省热门兜底推荐全靠它。behavior 用户行为表id、user_id、pet_id、behavior_type1 浏览 2 点赞 3 收藏 4 咨询、score对应的虚拟评分、create_time。这张表是整个推荐系统的数据地基每一条用户行为都要往这里写。我额外多说一句点赞数、收藏数不要冗余存到 pet 表里全部从 behavior 表实时 count 或定期汇总否则数据不一致的时候你会非常痛苦。adoption 领养申请表id、user_id、pet_id、reason、status待审核/通过/拒绝、create_time。这里分享一个 MyBatis-Plus 的小技巧正好对应很多人问的mybatisplus根据java实体类生成创建表的sql语句在实体类上用 TableName 指定表名用 TableId(type IdType.AUTO) 标记自增主键其余字段用驼峰命名然后在 application.yml 里设置ddl-auto: update启动项目时框架就会根据实体类自动建表或更新表结构。毕设阶段用这个方式省时省力不用手写一堆 CREATE TABLE。注意这是开发期的便利手段生产环境正规做法是用 Flyway 管理 DDL答辩被问到也能答出来。2.4 系统分层与推荐请求链路架构上我建议按标准的四层来组织package 结构要清晰这是答辩时加分项controller 层接收请求、参数校验、返回页面或 JSON。service 层业务逻辑编排调用 mapper 和推荐引擎。mapper 层MyBatis-Plus 提供的 BaseMapper 继承接口。engine 层独立出一个 recommend 包专门放相似度计算、推荐召回、排序融合与业务逻辑解耦。再把首页推荐这条请求链路完整走一遍用户在浏览器打开首页 → 请求进入 RecommendController → 调用 RecommendService → 先查本地缓存/Redis有 TopN 就直接返回 → 缓存没有从 behavior 表加载当前用户最近行为 → 在内存中构建用户-宠物评分矩阵或直接复用离线算好的相似度矩阵→ 用 ItemCF 计算候选宠物得分 → 乘上热门权重、加上冷启动策略补充的新品 → 排序取前 N 条 → 查 pet 表补齐宠物详情 → 返回 Thymeleaf 渲染页面。这条链路你要能不看代码在答辩时讲出来评委基本就认可你的系统设计能力了。3. 核心模块实现与实操细节3.1 数据埋点推荐系统最容易被忽略的地基我见过不少同学花大力气写算法结果推荐结果全为空查到最后发现 behavior 表里一条数据都没有。没有行为数据再好的算法都是空中楼阁。所以先讲埋点怎么做。我的方案是主动上报加兜底拦截双管齐下。主动上报适用于明确动作收藏按钮点击、点赞点击、咨询按钮点击前端用 AJAX 异步调用/behavior/record接口携带 petId 和 behaviorType。兜底拦截适用于浏览行为后端写一个拦截器或过滤器当请求进入宠物详情页/pet/detail/{id}时自动记录一条浏览行为不需要前端配合。两种方式互补既能保证行为类型准确又不漏记浏览数据。前端上报一段示意代码function recordBehavior(petId, type) { // type: 1浏览 2点赞 3收藏 4咨询 fetch(/behavior/record, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({petId: petId, behaviorType: type}) }).catch(err console.error(行为上报失败, err)); }后端接收时要注意一个细节同一用户对同一宠物重复浏览不要无限新增记录应该先查最近是否有同类型记录有则更新 create_time 和 score没有才插入新记录。否则一个用户手滑刷新十次页面行为表里十条相同浏览记录评分矩阵会被严重污染。3.2 ItemCF 推荐引擎的 Java 实现核心部分来了。先把评分规则定义清楚因为宠物网站没有用户显式打分只有隐式行为我们必须把行为换算成虚拟评分。我用的权重是浏览 1 分、点赞 2 分、收藏 3 分、咨询 5 分。咨询行为的权重最高因为它代表用户的真实领养意向。ItemCF 的完整实现分三步。第一步从 behavior 表加载数据在内存构建一个MapLong, MapLong, Double结构外层 key 是用户 ID内层 key 是宠物 IDvalue 是对应的评分。第二步计算宠物两两之间的相似度公式用余弦相似度两边都评分过的用户交集越大、分数越接近相似度越高。第三步根据目标用户已经评分过的宠物找出相似度最高的宠物集合按相似度加权求和后排序取前 N 个。相似度计算的核心代码骨架如下public class ItemCfRecommender { // 用户ID - 宠物ID - 虚拟评分 private MapLong, MapLong, Double userPetRatings; // 计算宠物a和宠物b的余弦相似度 public double calcSimilarity(Long petA, Long petB) { SetLong usersA getUsers(petA); SetLong usersB getUsers(petB); if (usersA.isEmpty() || usersB.isEmpty()) { return 0.0; } // 同时对两个宠物有行为的用户集合 SetLong commonUsers new HashSet(usersA); commonUsers.retainAll(usersB); if (commonUsers.isEmpty()) { return 0.0; } double dot 0.0; // 分子评分乘积之和 double normA 0.0; // 分母宠物a评分向量的模 double normB 0.0; // 分母宠物b评分向量的模 for (Long userId : usersA) { double scoreA userPetRatings.getOrDefault(userId, Collections.emptyMap()) .getOrDefault(petA, 0.0); double scoreB userPetRatings.getOrDefault(userId, Collections.emptyMap()) .getOrDefault(petB, 0.0); dot scoreA * scoreB; normA scoreA * scoreA; normB scoreB * scoreB; } if (normA 0.0 || normB 0.0) { return 0.0; } return dot / (Math.sqrt(normA) * Math.sqrt(normB)); } private SetLong getUsers(Long petId) { // 遍历 userPetRatings 找出所有给该宠物评过分的用户 } }这里有个实操要点不要每次请求都实时计算全量相似度矩阵。宠物数量上千之后两两组合是百万级计算量响应会非常慢。正确做法是启动时或每日凌晨用定时任务计算一次相似度矩阵序列化后存到本地缓存或 Redis在线推荐时直接查矩阵。这样系统架构从实时计算变成离线计算 在线召回答辩讲到这一层会显得非常专业。3.3 冷启动与混合召回没数据也要有东西可推冷启动是推荐系统绕不开的话题也是答辩评委最容易追问的点。两个方向都要提前准备好方案。新用户冷启动。用户刚注册没有历史行为ItemCF 直接失效。我的做法是两步注册时让用户勾选偏好标签比如喜欢猫咪/喜欢狗狗/接受大型犬推荐时优先返回标签匹配分类中最热门的宠物这部分用 view_count 排序即可。如果用户没有勾选标签就用全站热门榜兜底。这个方案逻辑简单、效果直观演示时给评委看从注册到首页有推荐的完整流程说服力很强。新宠物冷启动。刚上架的宠物没有被浏览过进不了相似度矩阵永远不会被推荐到。解决思路是给新鲜度留出曝光位推荐结果里固定留出 20% 的位置从最近 7 天上架且状态为上架的宠物里按浏览量排序补充。这叫探索与利用问题的朴素解法虽然简单但能保证内容多样性和平台生态健康。再谈谈混合推荐。我只用一路 ItemCF 太单薄建议用表格把召回来源列清楚召回来源权重说明ItemCF 协同过滤0.6核心算法基于行为的相似推荐热门榜兜底0.2全站浏览量前 50解决冷启动偏好标签匹配0.2基于品种、分类的内容匹配最终得分等于三路结果的加权和。同时加入随机扰动因子让同一个用户多次刷新时推荐列表不完全一样否则永远看到同一批宠物体验很差答辩时也会被质疑。3.4 前端页面与检索展示的落地细节前端页面不用做多花哨但关键页面必须齐整首页推荐位、宠物列表页、宠物详情页、搜索结果页、个人中心、登录注册页、后台管理页。首页布局我建议从上到下依次是搜索栏、分类快捷入口、个性化推荐楼层、猜你喜欢列表。个性化推荐楼层直接调用推荐接口这层就是答辩时的核心展示点。宠物详情页一定要加相似宠物推荐区域调用 ItemCF 的单点相似结果这能让评委直观感受到推荐算法的作用看了柯基旁边推荐柴犬、边境牧羊犬逻辑一目了然。搜索和筛选实现起来比较简单用 MyBatis-Plus 的分页插件就可以。关键词搜索用LIKE查询筛选条件动态拼接 QueryWrapper。但注意一点搜索和推荐是两个不同的入口搜索解决的是用户明确想要什么推荐解决的是用户可能想要什么不要混为一谈。搜索页直接按浏览量或时间排序就可以不用上算法省时间和精力。宠物卡片展示时可以把收藏数、咨询数显示出来一方面提升页面真实感另一方面暗示用户这些宠物受欢迎这对推荐系统的整体观感也有帮助。3.5 测试数据模拟与系统测试准备这是很多同学翻车的地方系统没数据推荐结果是空列表答辩时当场演示直接尴尬。必须在答辩前造出一批合理的行为数据。我通常写一个简单的 Java 或 SQL 脚本模拟 50 个用户、每人对 20 到 60 个宠物产生行为。行为分布要模拟现实热门宠物被大量用户浏览收藏小众宠物只有少数用户关注。这样相似度矩阵才有区分度推荐结果才有规律可循演示时能够讲出因为这个用户收藏了 A 和 B所以系统给他推荐了与它们相似的 C这种有依据的话。单元测试也不能少。最值得写的是推荐引擎的测试用例构造一个极小的样本集比如 3 个用户、4 个宠物、已知行为矩阵断言用户 1 的 Top2 推荐结果应该包含宠物 D。这样的测试既证明了你的逻辑正确又能在答辩时展示你具备测试意识。接口层面至少用 Postman 把注册、登录、宠物列表、推荐接口跑通一遍截图留作论文测试章节的材料。4. 常见问题与排查技巧实录4.1 新用户看不到任何推荐内容现象是登录后首页推荐位一片空白。排查顺序我固定按三条走首先看 behavior 表有没有当前用户的行为记录新用户没有行为是正常的这时候必须走冷启动逻辑其次看冷启动逻辑的代码分支是否被触发检查推荐 Service 里用户偏好标签是否为空、热门榜查询是否返回了数据最后看推荐接口返回的列表是不是空集合被前端遗漏处理。90% 的情况是热门兜底没做好把全站浏览量前 50 的查询补上问题就解决了。4.2 相似度算出来全是 0推荐完全没规律这种情况常见于测试数据太稀疏。如果每个宠物只有一两个用户产生过行为两个宠物之间几乎不可能有共同用户相似度自然全是 0。解决方法有两个方向把相似度计算从共同评分用户调整为基于宠物属性内容的相似度兜底比如同品种、同分类就算一个基础相似分或者把数据造密确保每个宠物至少有 10 个以上的用户行为覆盖。实操后你会发现行为数据的数量和质量直接决定推荐效果这也正是论文里可以写的实验结论。4.3 推荐列表永远一样用户点几次就腻了同一个用户每次进入首页推荐结果完全一致这通常是没加随机扰动或者排序完全确定导致的。我的做法是在最终排序分数上乘以一个0.95 Math.random() * 0.1的扰动系数让顺序在相邻名次间微微波动。另外可以做曝光过滤同一个宠物在 24 小时内对一个用户最多展示 3 次考虑把最近一次展示时间存到缓存里推荐时过滤掉已超过展示上限的宠物。这个小优化在演示时很出效果可以让评委看到你对用户体验有思考。4.4 数据量增长后推荐接口响应越来越慢如果 behavior 表已经攒了几万条数据每次请求都全表扫描再叠加相似度计算接口慢是必然的。我的做法是先加索引behavior 表的user_id create_time联合索引、pet_id普通索引SQL 里只查最近 90 天数据行为数据太老的意义不大。然后再加上本地缓存TopN 结果缓存 10 分钟相似度矩阵启动时加载一次热点宠物详情页缓存 30 分钟。做完这一套响应时间从几秒降到几十毫秒是完全可以实现的。如果这时再遇到 404 或 500基本是接口路径错误或缓存序列化问题按常规排查即可。4.5 答辩高频问题与应对思路我每年都能听到评委问出高度相似的问题提前准备好答辩就不虚。为什么用 ItemCF 而不是 UserCF答宠物之家物品数量少、更新慢用户偏好相对稳定ItemCF 可以离线计算相似度矩阵在线复用UserCF 更适合新闻短视频等物品快速变化的场景。加上 ItemCF 推荐结果可解释性强能直接展示因为你看了柯基所以推荐柴犬。用户没有打分你的评分哪里来的答采用隐式反馈转虚拟评分浏览 1 分、点赞 2 分、收藏 3 分、咨询 5 分权重根据行为对用户意向的表达强度设定。如果有精力可以补一句这是基于业务经验的设定后续可用回归分析优化权重这个回答非常加分。推荐效果你怎么评估答离线阶段用精确率和召回率构造测试集验证推荐命中率在线阶段可以统计推荐位的点击率。毕设层面重点是把评估流程设计出来真实数据可以后续积累。如果用户量到百万级你的系统还扛得住吗答当前架构面向中小规模场景后续扩展方向是引入 Redis 集群缓存、用消息队列异步处理行为数据、相似度计算转向离线计算框架。表现出清晰的扩展意识即可不用真的实现。其实每次带学生做完这个题目我最大的体会是毕设的价值不是算法多先进而是把一个完整的系统从零到一跑通的能力。推荐算法再朴素只要数据链路完整、逻辑闭环、能讲清楚为什么这么设计就已经是一份优秀的本科毕设了。反而那些上来就想堆深度学习模型的最后往往挂在数据处理和环境配置上连演示都跑不起来。最后再分享一个实战小技巧做这个项目时把行为数据表先造好、埋点先打通再去调推荐算法。数据通了算法的效果一眼就能看到数据不通后面每一步都是在盲写。顺序对了这个题目你会做得非常顺手。后续如果想扩展往两个方向走比较容易出彩一个是在推荐结果里加入宠物相性匹配这类领域知识另一个是把推荐系统做成可配置的 A/B 测试框架让管理员在后台调整各路召回权重。这些点放到论文的展望里会让整篇工作的完整度更上一个台阶。