资讯详情

Spring Boot+协同过滤的化妆品推荐系统设计与实现

📅 2026/10/16 7:45:33 | 华诺云谱 👁 阅读
Spring Boot+协同过滤的化妆品推荐系统设计与实现
毕业设计选题年年都有新花样但“基于协同过滤的化妆品推荐系统”这个题目在 Spring Boot 技术栈的加持下确实是近年市面上出现频率很高的一个方向。它不只是一个普通的 CRUD 管理系统核心价值在于“推荐算法”的落地怎么把用户的历史行为、商品属性这些数据变成一套真正能猜中用户心思的智能导购逻辑。这篇文章我就以实际开发者的视角把标题里隐含的设计思路、算法选型、双维度协同过滤的实现细节以及实际开发中踩过的坑拆开揉碎了讲清楚。无论你是正在选毕业设计题目的在校生还是想转行做推荐系统方向的后端开发这篇内容都能让你少走不少弯路。1. 项目整体设计与思路拆解1.1 为什么选 Spring Boot 作为推荐系统的载体很多人一听到“推荐系统”第一反应是 Python、机器学习框架这类技术栈。但作为一个后端开发方向的毕业设计Spring Boot 反而是更合适的载体。Spring Boot 的核心优势在于快速搭建稳定的 Web 服务内置 Tomcat、自动配置、生态成熟拿来做一个前后端分离的推荐系统后端效率比想象中高很多。我在实际开发中体会到推荐系统本质上是由三个部分组成数据层用户行为数据、商品数据、算法层协同过滤计算相似度、生成推荐列表、应用层暴露 RESTful 接口给前端调用。Spring Boot 在这三个层面都能很好地履行职责数据层用 JPA 或 MyBatis 操作 MySQL算法层用 Java 编写协同过滤工具类应用层用 Controller 封装接口。整个项目结构清晰答辩的时候也能把系统架构讲得很明白。标题里提到的“化妆品推荐系统”其实是个非常有代表性的业务场景。化妆品的 SKU 众多品类跨度大护肤、彩妆、香水、工具用户的选择成本高推荐系统的价值空间大。而且化妆品的用户行为数据有明显的长尾效应少数爆款商品贡献大部分销量但长尾商品也需要通过推荐触达用户。这种场景下协同过滤算法比单纯的基于内容的推荐更能挖掘用户潜在偏好。1.2 协同过滤 vs 基于内容的推荐为什么选前者在做技术选型时我认真对比过基于内容的推荐Content-Based和协同过滤Collaborative Filtering两条路线。基于内容的思路是分析商品本身的属性标签把“口红”推荐给浏览过“口红”的用户。逻辑简单但没有惊喜度推荐来推荐去都是同质化商品。协同过滤的思路则完全不同它不分析商品本身是什么而是通过用户的行为数据建立关联。用户A和用户B都买过同一支口红那么系统就会认为A喜欢的其他化妆品B也可能喜欢。这种方式能挖掘出用户自己都意识不到的潜在偏好。举个例子很多用户会在购买粉底液的同时购买美妆蛋这两者在商品属性上关联不大但对用户行为数据来说相关性极高。协同过滤能捕捉到这种跨品类的关联规则这是基于内容推荐做不到的。结合标题里“协同过滤”这个关键词我确定了核心算法路线UserCF基于用户的协同过滤和 ItemCF基于物品的协同过滤双轨并行再通过融合策略输出最终推荐结果。不过在实际开发中单一的协同过滤算法会面临冷启动、数据稀疏这些问题所以标题里提到“改进协同过滤”“双维度协同过滤”——这是整篇设计的灵魂所在后续章节我会详细拆解。1.3 双维度协同过滤这个“双维”到底指什么标题里“商品双维度协同过滤”这个表述我在最初设计时做了两种解读一种是“用户维度 商品维度”的双维度协同过滤另一种是“商品属性维度 用户行为维度”的双维度相似度计算。最终项目中我两种思路都用了。第一种“用户 商品双维度”是指系统同时运行 UserCF 和 ItemCF 两个算法各自生成一个推荐列表最后通过加权融合输出最终结果。UserCF 更适合用户量小、兴趣变化快的场景ItemCF 更适合商品数量大、用户稳定的场景。化妆品推荐系统的特征决定了这两个算法都不能舍弃但两者的权重配比需要调参。第二种“商品属性 用户行为”的双维度是指在计算商品相似度时不仅仅依赖“购买过A也购买过B”的共现次数还结合商品的品类、功效、适用肤质这些属性特征。这个改进的意义在后文会有详细说明这里先提一个概念纯行为协同过滤在面对新品时由于没有行为数据相似度矩阵里全是零整个推荐就崩了。引入商品属性维度后新品也能通过属性相似度进入推荐列表。2. 协同过滤算法核心解析原理与改进方向2.1 UserCF 与 ItemCF 的数学表达先过一遍基础原理。基于用户的协同过滤UserCF核心逻辑是对目标用户 u找出与他行为最相似的 K 个用户把这 K 个用户喜欢过但 u 没有交互过的商品按相似度权重排序推荐给 u。用户相似度通常用余弦相似度或皮尔逊相关系数计算。余弦相似度的公式是设用户 u 和用户 v 的评分向量分别为 R_u 和 R_v相似度 sim(u, v) (R_u · R_v) / (|R_u| × |R_v|)。在化妆品场景里向量维度是商品取值可以简化为 0/1买过或没买过也可以用评分1-5星。但实际问题在于用户和商品数量都很多时向量高维稀疏余弦相似度的分母可能为0。我采用的改进策略是加入共同评分商品数量的惩罚项只有共同交互过的商品数量超过阈值时才计算相似度否则直接设为0避免大量无意义的计算。ItemCF 的逻辑则相反先计算商品两两之间的相似度然后根据用户历史偏好的商品去推荐“与这些商品相似”的其他商品。商品 i 和商品 j 的相似度最经典的计算方式是sim(i, j) |N(i) ∩ N(j)| / sqrt(|N(i)| × |N(j)|)其中 N(i) 是购买过商品 i 的用户集合。这是 Jaccard 相似度的一个变体能有效避免爆款商品过度主导相似度结果。2.2 冷启动问题的三种解法冷启动是协同过滤的头号痛点。新用户没有任何行为数据UserCF 根本找不到相似用户新商品没有交互记录ItemCF 的相似度矩阵里它是孤立点。我在项目中设计了三个层次的解法第一层新用户冷启动。注册时引导用户选择关注的化妆品品类、肤质类型、价格区间。这些偏好标签不在协同过滤算法里用而是先走基于内容的推荐给用户推送对应品类的热门商品。等用户产生足够行为数据点击、收藏、加入购物车、购买后再切换为主要走协同过滤。第二层新商品冷启动。新商品上架时后台录入商品属性标签品类、功效、适用肤质、品牌定位、价格带通过属性相似度找到最相似的几个老商品先把新商品插入到 ItemCF 的相似度矩阵里让它在推荐列表中拥有初始曝光机会。第三层混合推荐策略。API 层做熔断和降级如果协同过滤模块计算出来的推荐列表为空极端稀疏场景自动切换到“热门商品 品类偏好”兜底策略保证接口永远有数据返回。2.3 改进点融合商品属性的相似度计算对于 ItemCF我做了核心改进。传统的商品相似度只基于用户行为共现对于“SKU 多、上新快”的化妆品行业来说不太够用。我引入了属性相似度的计算每个商品用一个 one-hot 编码的属性向量表示比如一款产品可以表示为[品类精华, 功效保湿, 功效美白, 肤质干性, 价格带200-400]商品 i 和商品 j 的属性相似度 attr_sim(i, j) 共同命中的属性数 / 总属性数。最终的相似度矩阵采用线性融合final_sim(i, j) α × behavior_sim(i, j) (1 - α) × attr_sim(i, j)调参过程中α 取 0.7 左右效果最好。太高了新品依然出不来太低了行为数据的信息没有被充分利用。这个 α 不能拍脑袋定死我在后台做了一个动态配置接口方便在测试阶段反复调整。2.4 用户相似度计算的工程优化实际落地 UserCF 时会遇到一个很现实的问题用户量上了几百上千以后两两计算相似度的复杂度是 O(n²)这是不可接受的。我在项目中采用了“倒排索引 共现矩阵”的优化手段先从行为表中找出每个用户交互过的商品集合然后遍历每个商品把购买过该商品的用户两两配对累加共现次数。这样只需要遍历商品数量级别的数据而不是用户数量的平方。还有一个过滤策略在计算用户相似度之前先进行一次粗筛选只保留“共同购买过至少2个商品”的用户对进入细粒度相似度计算其余直接舍弃。这个阈值让计算量大幅下降而且推荐精度反而提高了——因为只共同买过1个商品的用户相似度信号太弱引入后大多是噪声。3. Spring Boot 系统架构与数据层设计3.1 整体技术选型与分层架构推荐系统的后端采用经典的分层架构Controller 层负责接收前端请求Service 层承载业务逻辑和推荐算法调用Repository 层操作数据库。技术选型上Spring Boot 2.7.x MyBatis-Plus MySQL 8.0 Redis前端配合 Vue Element UI 做管理后台用户端走微信小程序或 H5。Redis 在整个系统中扮演的角色比想象中重要。用户-商品交互矩阵和商品相似度矩阵如果每次请求都实时从 MySQL 读出来计算响应时间会爆炸。我的做法是离线计算任务定期把相似度矩阵写入 Redis线上推荐接口直接从 Redis 读取缓存命中后推荐响应时间能压到 50ms 以内。用户行为数据写入采用异步方式。用户每次点击商品、收藏、加购前端调用行为上报接口后端 Controller 接住请求后直接放入线程池或消息队列立即返回成功由异步任务批量写入 MySQL。这样保证了推荐系统的主链路不受行为数据写入的拖累。3.2 数据库表结构设计要点化妆品推荐系统的数据表比普通管理系统多了几张核心表。用户表、商品表、品类表这些基础表不赘述了重点说几张与推荐算法直接相关的表用户行为记录表user_behavior字段包括用户ID、商品ID、行为类型浏览/收藏/加购/购买、行为分值、创建时间。推荐算法读取这张表生成协同过滤的用户-商品交互矩阵。商品属性表product_attr这张表的存在是“改进协同过滤”的基石。商品ID、属性类型品类/功效/肤质/价格带/品牌、属性值。每个商品可以有多条属性记录属性向量由这张表组装生成。相似度结果表similarity_result商品ID_A、商品ID_B、相似度值、维度类型行为相似或属性相似。这张表是算法计算后的成品离线任务算完后写入推荐接口直接查。这张表设计的关键点是以“行为类型 行为分值”的方式归一化用户行为强度。我采用的规则是浏览记1分、收藏记3分、加购记5分、购买记10分。这个分值不是拍脑袋定的而是参考了电商行业的通用经验购买行为的权重至少是浏览的5倍以上否则推荐结果会被“随便看看”的噪声数据带偏。3.3 核心接口设计规范推荐系统对外暴露三类接口。第一类是行为上报接口前端在用户浏览商品详情页、点击收藏、提交订单等时机异步上报行为数据。第二类是推荐查询接口传入用户ID、场景类型首页推荐、相似商品推荐、购物车关联推荐和返回数量后端返回商品列表带推荐理由。第三类是后台管理接口用于配置算法参数相似度融合权重、推荐列表商品数量上限。推荐接口的响应数据结构我做了统一约定返回商品ID、商品名称、主图URL、价格、推荐分数、推荐理由。推荐理由字段是加分项前端展示“因为你看过XX推荐这款XX”之类的文案能明显提升点击率。4. 双维度协同过滤的落地实现4.1 第一维度基于用户行为的协同过滤实现现在进入核心代码落地环节。第一维度是用户行为维度的协同过滤我拆成三个步骤来实现。第一步从数据库加载用户行为数据构建原始交互矩阵。使用一个 Map 结构键是用户ID值是另一个 Map记录该用户对所有商品的行为分值。这里的关键是只加载行为分值大于0的记录避免把负反馈比如用户明确不喜欢的商品混入矩阵。第二步计算用户之间的相似度矩阵。用倒排索引的方式先遍历商品的用户列表对每个商品的用户列表进行两两配对累加共现次数和共现得分。由于 UserCF 需要的是“相似用户集”所以这步产出的结果集是每个用户对应的 Top N 相似用户列表。第三步为目标用户生成推荐列表。遍历相似用户的交互商品排除目标用户已经交互过的商品按“相似度权重 × 行为分值”加权累加取总分最高的前 K 个商品。K 的取值我一般设 20返回给前端时再根据业务规则过滤掉售罄商品和下架商品。4.2 第二维度基于商品属性与行为的融合相似度第二维度融合了行为相似度和属性相似度核心在于属性向量的构建和融合相似度计算。商品属性 from product_attr 表加载后转成属性集合的二进制编码或 one-hot 表示。属性向量空间的设计要控制维度不能把每个属性值都当作独立一维否则维度爆炸。我把属性划分为五个维度品类眼影/口红/精华/面霜等、功效保湿/美白/抗皱/控油等、适用肤质干皮/油皮/混油/敏感肌、价格带0-100/100-300/300-500/500、适用场景日常通勤/约会派对/敏感期修复。每个维度内部做 one-hot 编码但维度之间不交叉。最终属性向量是一个固定长度的稀疏向量通过计算两个向量的余弦相似度或杰卡德相似度得到属性相似度。然后执行加权融合final_sim(i, j) α × behavior_sim(i, j) (1 - α) × attr_sim(i, j)。其中 behavior_sim 直接采用 ItemCF 算出的行为相似度。这里要注意行为相似度矩阵的稀疏度远高于属性相似度矩阵因为每个商品都有属性但很多商品没有共同购买记录所以融合时需要对缺失值做处理——如果两个商品没有行为共现记录behavior_sim 记为0但最终相似度仍可能由属性维度支撑起来。这正好解决了冷启动商品的问题。4.3 实时推荐与离线计算的职责划分推荐系统工程落地时最常见的一个误区是纠结于算法复杂度却忽略了架构层面的设计。我做了一个清晰的职责划分离线计算部分每天晚上凌晨跑定时任务从 MySQL 增量读取当天的用户行为数据更新用户相似度矩阵和商品相似度矩阵计算双维度融合相似度把最终的 Top N 推荐列表写入 Redis。为什么算 Top N 而不是全量矩阵因为全量矩阵在用户量达到几万级别时存储量巨大而真正用到的只是每个用户的前 N 个推荐结果。实时计算部分用户白天产生行为时通过行为上报接口同步更新用户近期行为数据生成一个“实时兴趣向量”与 Redis 中的离线推荐列表做简单融合实时兴趣命中的商品排序置顶未命中但相似度高的商品排在后面。这种“离线为主 实时为辅”的架构既保证了响应速度又能捕捉用户当下的兴趣变化。4.4 推荐理由的生成策略为了让推荐结果看起来不“硬”我在接口中加入了推荐理由。推荐理由不是算法硬性输出的而是根据推荐类型做模板映射。如果推荐商品来自 ItemCF 的相似度匹配理由就是“与你浏览过的XX相似”如果来自 UserCF 的相似用户偏好理由就是“和你品位相似的用户也喜欢XX”如果来自热门兜底理由就是“最近大家都在买XX”。这个细节在毕业设计中非常加分。答辩时老师通常会问“推荐结果的解释性如何”推荐理由功能恰好回答了这个痛点——推荐系统不只是黑盒输出还要能让用户理解“为什么推荐这个”。5. 常见问题与排查技巧实录5.1 相似度矩阵偏斜爆款商品绑架推荐结果我测试时发现一个很典型的问题某款口红是爆款购买记录非常多ItemCF 计算出来几乎所有热门商品和它都有较高的相似度。推荐结果里爆款商品的相似商品霸占了大部分位置用户真正需要的小众商品反而排不上来。排查思路是打印出爆款商品与其他商品的相似度分布发现行为相似度在爆款场景下已经失真。解决办法有两个一是做相似度归一化将每行相似度除以该行最大值压制过热商品的扩散效应二是在最终推荐打分时加入商品热度惩罚因子推荐分数乘以一个递减的权重函数避免高热度商品无限挤压长尾商品。两个策略叠加后推荐列表的多样性明显提升。5.2 用户行为稀疏交互矩阵大量为零毕业设计的数据量级通常不大学生用户往往只有几千条模拟数据。在这种稀疏场景下协同过滤的效果可能远不如预期大量用户的推荐结果基本是“热门商品集合”失去了个性化。排查后发现关键在于行为数据本身不够丰富。解决办法是增加模拟数据的生成逻辑不光是随机购买记录而是按照用户的注册标签品类偏好、价格带来生成行为数据保证每个用户有10条以上的有效交互记录。同时算法层面降低相似用户的 K 值从20降到10因为数据稀疏时K值太大会引入大量弱关联用户。5.3 推荐接口响应过慢实时计算阻塞主线程早期版本推荐接口在处理请求时需要实时从 MySQL 加载用户行为数据做计算用户量稍涨后接口响应时间直接从 50ms 飙升到 3 秒。排查用 Arthas 的 trace 命令追踪调用链路发现瓶颈在数据库查询和相似度计算的 CPU 密集型操作上。解决方案分两步一是在 Redis 中缓存相似用户列表和相似商品列表推荐接口直接从缓存取数不穿透到数据库二是引入异步线程池行为上报接口不再同步处理数据而是放入队列延迟处理让主接口只做轻量级读写。改造后推荐接口99%的请求在80ms内完成稳定性和响应速度都达标了。5.4 双维度权重敏感α 参数调优的经验值融合相似度的权重 α我在测试中发现它对推荐结果影响极大。α 1.0 时系统退化为纯行为协同过滤新品完全无法推荐α 0.3 时属性维度占据主导推荐结果面向所有用户高度类似个性化程度下降。最终采用的自适应策略是按商品类型的“行为数据丰富度”动态调整 α。对新品和长尾商品行为数据少α 自动降低到 0.5对爆款商品行为数据丰富α 拉高到 0.85。动态调整后整体推荐效果提升明显。5.5 冷启动用户推荐空列表的兜底策略测试场景中有大量新注册用户行为记录为空协同过滤推荐结果为空。早期版本直接返回空列表前端展示为空白体验极差。解决思路是构建三层兜底第一层按用户注册时填写的肤质、品类偏好推荐对应属性相似的商品第二层推荐全站近7日热度最高的20款商品第三层如果前面两层都空极少见则按商品ID排序返回默认列表。兜底策略让推荐接口永远不会返回空数据。6. 毕业设计答辩与项目扩展经验6.1 答辩时最容易被打动的技术亮点毕业设计答辩老师通常更关注你自己动手解决的实际问题而不是背了多少概念。我复盘过自己项目里最有价值的几个技术亮点值得在答辩中展开第一个亮点是双维度融合相似度的设计。我从“纯行为协同过滤无法处理新品冷启动”这个痛点出发引入属性相似度做补充并且设计了可动态调节的融合权重这属于对经典算法的改进和创新比单纯实现一个协同过滤更有说服力。第二个亮点是离线 实时双通道推荐架构。离线定时任务计算相似度矩阵实时行为流更新用户兴趣两者通过 Redis 衔接。这个设计让推荐系统具备了生产级别的性能思维是很好的加分项。第三个亮点是推荐理由生成策略。推荐理由让算法结果从黑盒变成可解释的在系统演示环节能直观地让用户看到推荐系统的“思考过程”非常有说服力。6.2 项目未来可扩展的方向一个项目做完了还能怎么扩展也是答辩时老师常问的开放式问题。我的规划是三个方向第一加入深度学习排序模型用用户行为序列作为输入做点击率预估替换现在的“推荐分数加权排序”。第二引入知识图谱把化妆品的成分、功效、适用肤质的关系建图实现解释性推荐和基于知识路径的推荐。第三做多目标优化不只考虑点击率还要关注推荐列表的多样性和新颖度避免信息茧房。6.3 给即将动手的同学几点避坑建议最后分享几条实操层面最关键的避坑建议数据坑不要等到代码写完才开始造数据。推荐算法非常依赖数据质量建议第一天就开始用脚本生成模拟的“用户画像 行为序列”并让数据在分布上尽量贴近真实场景——热门商品集中、长尾商品稀疏、用户兴趣有聚类特征。算法坑推荐算法代码建议单独写一个模块不要和 Controller、Service 混在一起。毕业设计的代码后期要反复调试算法参数独立模块方便使用单元测试和 JUnit 测试单独评估算法效果。性能坑即使只有几百个用户Resis 缓存和离线计算的架构也要做出来因为这是你答辩时说“性能优化”的底气。等答辩完再补这个架构成本会大得多。我的经验是这类项目的核心不在 Spring Boot 本身而在于你能不能把算法和工程有条理地结合让推荐结果既“有道理”又“有响应速度”。抓住双维度协同过滤这个核心创新点加上合理的系统架构和充分的测试数据完成度和答辩效果都不会差。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑