☰
基于大数据与Spark的图书推荐系统实战:从Hive数仓到ALS算法
2026/9/29 23:06:55 网站建设 项目流程

做“基于大数据的图书推荐系统”这类项目,我前后完整写过两个版本,一个是为了应付课程设计的简化版,一个是真正上了Hadoop和Spark集群的完整版。第一次接到这个题目时,我也以为推荐系统的核心就是把协同过滤算法跑通,但真做下来才发现,算法只占了整个项目的一小半,数据采集、清洗、数仓分层、集群部署、前后端联调、算法评估,每一环都能把人逼疯。这篇文章就是基于我自己完整做完这个项目的经验整理出来的,从需求拆解到技术选型,从Hive数仓到Spark的ALS推荐实现,再到最后的可视化展示和问题排查,尽量把每一步为什么要这么做讲清楚,而不是只丢给你一堆代码。

这个项目适合谁?如果你是大数据专业或计算机相关专业的学生,正在做毕业设计;或者你想把大数据技术栈的完整链路实战一遍;又或者你已经在工作,想通过一个具体业务场景把HDFS、Hive、Spark这些工具串起来,那这篇文章会非常对路。我会尽量用从业者之间交流的方式来讲,少废话,多干货,该贴代码的地方贴代码,该给参数的地方给参数。

1. 项目整体思路与需求拆解

1.1 这个项目到底要解决什么问题

图书推荐系统,说白了就是解决“用户面对海量图书不知道看什么”的问题。传统图书网站靠分类浏览和搜索,用户主动找书,而推荐系统是被动推荐——根据用户的历史行为,猜测他可能对哪类书感兴趣,然后把书推到用户眼前。这里的核心关键点在于“大”字:用户量大、图书量大、行为数据量更大。当数据量到了千万条甚至上亿条记录,单机数据库和各种简单的SQL统计已经扛不住,必须引入分布式存储和计算。

毕业设计里遇到这类题目,老师通常不会只关注推荐算法本身,还会看你的系统是不是有一套完整的数据处理链路:数据从哪来、怎么存储、怎么清洗、怎么建模、模型怎么服务、结果怎么展示。所以我在设计这个项目时,特意把它拆分成五层:数据采集层、数据存储层、数据处理层、推荐引擎层、应用展示层。每一层对应一到两个技术组件,层次清晰,答辩的时候也容易讲明白。

还有一个容易被忽视的点:推荐效果怎么评估。很多同学把推荐结果做出来就结束了,但一个合格的系统必须回答“推荐得准不准”。我后面会讲怎么切分训练集和测试集,怎么计算精确率、召回率、RMSE这些指标,这部分在论文里是加分项。

1.2 技术栈选型背后的逻辑

我最终选定的技术栈是:爬虫用Python + requests + BeautifulSoup,数据仓库用Hive,计算引擎用Spark,推荐算法用Spark MLlib自带的ALS,后端用Spring Boot,前端用Vue + ECharts,数据缓存和热门榜用Redis。

很多人会问:图书推荐这种体量,用MySQL加内存计算不就够了吗?为什么非要搭一套Hadoop生态?这个问题我论文答辩时也被老师问过。我的回答是:如果是几千本书、几百个用户的玩具项目,MySQL确实扛得住,但你要思考这个系统设计的初衷——它是为大规模场景设计的。单机计算在数据量达到一定量级后,相似度矩阵的存储和计算会呈指数级增长。比如10万个用户,拿去重后的用户对物品操作记录构建共现矩阵,单机内存根本放不下。而HDFS加Spark天然支持横向扩展,数据放不下就加节点,计算跑不动就分布式并行。这个设计不是炫技,而是让系统具备可扩展性。

另一个关键选择是为什么用ALS而不是别的算法。早期我试过直接用Python手写基于物品的协同过滤,在小数据集上效果还行,但一旦数据量上来,光构建物品相似度矩阵就要迭代几十轮,而且Spark平台上的原生实现更稳定。ALS全名叫交替最小二乘法,特别适合处理用户对物品评分这种稀疏矩阵,它把高维的用户-物品评分矩阵分解成两个低维矩阵的乘积,在分布式环境下每一步都能并行计算。这是它在海量数据场景下成为主流的原因。

1.3 系统模块划分与数据流

整个系统的数据流是这样的:爬虫采集图书基础信息和用户评分记录,落盘为CSV或JSON文件,上传到HDFS;接着通过Hive把原始数据加载进ODS层,经过数据质量校验和清洗后进入DWD层,再在DWS层做数据聚合,形成用户行为宽表和图书特征宽表;Spark读取宽表数据,训练ALS模型,生成每个用户的Top N推荐结果和每个图书的相似图书列表,写回MySQL和Redis;后端Spring Boot提供RESTful接口,前端调用接口把推荐结果渲染到页面上。

我画一张简表来对比各层职责,让你一眼看明白:

层级核心组件职责关键技术点
数据采集层Python爬虫采集图书信息、评分记录反爬策略、数据验证
数据存储层HDFS + Hive原始数据存储、数仓建模分区表、文件格式转换
数据处理层Spark + HiveETL清洗、特征工程数据去重、异常值过滤
推荐引擎层Spark MLlib ALS离线训练模型、生成推荐模型调参、相似度计算
应用展示层Spring Boot + Vue接口服务、可视化展示Redis缓存、前端交互

这个架构在答辩和实际开发中都非常好讲,从下往上,每一层都有输入输出,逻辑链条完整。

2. 数据层设计与实现:从采集到数仓

2.1 图书数据采集与预处理

图书基础信息从哪里来?我是从主流图书平台的公开页面抓取的,包括书名、作者、出版社、出版时间、分类、定价、封面图、简介、标签和用户评分。爬虫部分大概400行Python代码,requests负责请求页面,BeautifulSoup解析HTML。这里要给第一次写爬虫的同学提个醒:抓页面前先通过浏览器的开发者工具确认数据是直接渲染在HTML里的,还是通过AJAX接口异步加载的。我最初盯的是详情页的服务端渲染字段,后来发现某些平台的评分和评论数走的是独立接口,导致解析出来的数据大量为空,白白浪费了大半天。

抓取过程中一定要控制请求频率,我每抓完一个页面sleep 1到2秒,同时通过伪造随机User-Agent来降低被识别拦截的概率。数据量不大,抓个两万本足够了,没必要追求全量,关键是覆盖的类别要广,文学、社科、科技、历史、经济、少儿这些大类都要有,这样推荐算法才不至于因为数据太偏而失去参考价值。

清洗这一步容易踩坑。原始数据里经常出现重复书籍(同一本书不同平台收录),我按“书名+作者+出版社”三个字段做组合去重。缺字段的处理策略是:出版社缺失用“未知出版社”填充,价格缺失用同类书籍的中位数插补,分类字段缺失之间丢弃——分类是后面做基于内容推荐和冷启动推荐的关键特征,这一列不能有太多空值。还需要把所有评分归一化到1到5分之间,原始平台用的是10分制,不归一化后面ALS模型就没法用。

2.2 用户行为数据的模拟与生成策略

这里要坦率地承认:图书推荐作为个人项目,很难拿到真实的海量用户行为数据。我采用的方案是用Python脚本基于统计分布模拟生成。

用户的活跃度遵循长尾分布。按照真实推荐场景的观测,少量用户贡献了大部分行为,所以我让20%的用户产生80%的评分行为,行为数量从几十条到上千条不等。评分值的分布也要贴近现实,我给均值设置为3.8分,标准差0.9,截断在1到5分之间。这样生成的评分不是均匀分布,而是集中在3到5分之间,符合豆瓣等平台高分书多的现实情况。

关键的一步是模拟“用户对已浏览图书的评分倾向”。我用了一个简单但有效的方法:先随机为该用户分配3到5个偏好标签,比如偏好“科幻”“历史”或“计算机”,然后从图书数据中筛选出标签相符的书籍,按照一定概率赋高分。这样生成的评分矩阵天然带有一定的偏好结构,ALS算法才能从中学习到用户和物品的潜在因子。如果完全随机生成评分,推荐效果会非常差,你会在评估阶段发现精确率低得没法看。

我模拟了5万用户,给他们分配累计150万条行为记录,同时包含点击、收藏、评分三种类型,存入本地文件。行为时间戳控制在最近12个月内,方便后面按时间划分训练集和测试集。

2.3 Hive数仓分层设计与HDFS存储

HDFS上我按数仓分层建目录:/data/books/ods、/data/books/dwd、/data/books/dws。原始CSV文件先落在本地,通过hadoop fs -put命令上传到ODS目录。然后建Hive外部表,方便HDFS文件位置变化时依然能访问。

下面是我建的图书基础表结构,主表按日期分区:

CREATE EXTERNAL TABLE dim_book_info ( book_id BIGINT, book_title STRING, author STRING, publisher STRING, category STRING, price DOUBLE, pub_date STRING, avg_score DOUBLE, tags STRING ) PARTITIONED BY (dt STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE LOCATION '/data/books/dwd/dim_book_info';

ODS层到DWD层,我做了一件事:把清洗逻辑固化成HiveSQL。比如去重用row_number() over(partition by book_title, author, publisher order by avg_score desc),取rn=1的记录;价格异常值通过where price between 0 and 1000过滤;评分归一化通过case when avg_score > 10 then avg_score / 2 else avg_score end实现。

需要说明的是,实际生产一般会用Parquet列存格式来加速查询,配合同目录下的ERC文件格式压缩能大幅减少存储开销。但课堂项目用TEXTFILE比较容易调试排错,这算是我刻意保留的一个“教学性”选择。

2.4 ETL调度与数据校验

数据从ODS到DWD不是跑一次就完事,我写了一个简单的Shell脚本,按日期递增批量执行HiveSQL,并把执行日志输出到指定目录。脚本逻辑很简单:

#!/bin/bash dt=$1 hive -e " INSERT OVERWRITE TABLE dwd_books.dim_book_info PARTITION(dt='$dt') SELECT ... FROM ods_books.ods_book_info WHERE dt='$dt'; "

ETL完成后必须做数据校验,这是很多初学者容易跳过但实际非常关键的环节。我每次跑完都会执行几个快速检查:主键是否唯一、空值率是否超过阈值、字段类型是否隐式转换出错。比如我遇到过一个问题:原始数据某条记录的分类字段带了\r换行符,导致Hive表该字段后面多出来一个不可见字符,看起来像文学\r,做category = '文学'的匹配死活匹配不上。排查半天,最后用trim()解决。这种坑只有实践才会遇到。

数据校验还可以借助Spark的DataFrame API做一次统计,计算每列的空值比例和不同值数量,快速发现数据质量问题。我建议把校验结果输出成JSON文件存档,答辩时能展示你的数据质量意识,这部分是普通学生项目里很少有的亮点。

3. 推荐算法核心实现

3.1 离线推荐:基于物品的协同过滤实现细节

我先用Spark实现了一版ItemCF作为基线,目的是和ALS做效果对比,这也是论文里很有价值的实验部分。基于物品的协同过滤核心思想是:如果大部分用户对物品A和物品B的行为一致,就认为物品A相似于物品B,推荐时把用户行为过的物品的相似物品挑出来。

相似度计算我用了余弦相似度加热度惩罚的版本。公式上先统计物品之间的共现次数,然后对热门物品降权:

sim(i, j) = sum_{u ∈ U_ij} (1 / log(1 + |N(u)|)) / sqrt(|N(i)| * |N(j)|)

用代码实现时,我直接用RDD做笛卡尔积然后聚合,因为当时对Spark SQL还不够熟。现在回头看,更推荐用DataFrame API加join实现,代码更简洁,性能也更好。大致流程:先由用户行为表做map转换成(userId, bookId),然后自连接生成(userId, (bookIdA, bookIdB)),过滤掉A与B相同的情况,按(bookIdA, bookIdB)分组统计count,再乘以1/log(1+用户行为数)的权重因子。最后按分母做归一化,取Top N。

ItemCF有一个天然缺陷:当图书数量级大且交互冷门时,相似度矩阵非常稀疏,很多书找不到近邻。这时候就要考虑到使用矩阵分解类算法,也就是接下来要说的ALS。

3.2 ALS矩阵分解:核心参数与训练流程

ALS是Spark MLlib里做推荐最成熟的算法。它的数学本质是把用户对物品的评分矩阵R(维度:用户数 × 物品数,极度稀疏)分解成两个稠密矩阵U和V的乘积,使得R ≈ U * V^T。优化目标是让U * V^T与R中已知评分项尽可能接近。交替最小二乘的含义是:固定U优化V,然后固定V优化U,迭代交替,直到收敛。

在Spark上的代码不长,我贴一下核心训练逻辑:

import org.apache.spark.ml.recommendation.ALS val als = new ALS() .setMaxIter(10) .setRank(10) .setRegParam(0.1) .setUserCol("userId") .setItemCol("bookId") .setRatingCol("score") .setColdStartStrategy("drop") .setAlpha(1.0) val model = als.fit(trainingData) val predictions = model.transform(testData)

这里每个参数的选择都不是随意的,简单拆解一下背后的考虑。

rank是潜在因子维度,决定了模型的表达能力。rank太小模型学不到深层特征,太大容易过拟合而且计算量激增。我测试过rank在10、20、50几档下的RMSE指标,20以上收益递减,最终选了20。regParam是正则化系数,用来防止模型在稀疏评分矩阵上过拟合,我通过网格搜索在[0.01, 0.05, 0.1, 0.5]里选了0.1。maxIter设10,测试后发现迭代超过10次之后RMSE下降幅度小于0.5%,为了控制训练时间就定为10。

setColdStartStrategy("drop")这个参数非常重要。默认策略在遇到新用户或新物品时会预测出NaN评分,导致整个DataFrame管道报错。设成drop后,缺失的预测值会被直接丢弃,保证任务能跑完。实际使用中还可以用"none"策略来保留NaN再填充默认值,但项目演示用drop最省心。

训练前我把数据按时间戳切分:最近20%作为测试集,其余80%作为训练集。为什么要按时间切分而不是随机切分?因为推荐系统的本质是预测未来行为,用过去预测未来,时间切分模拟了真实场景,评估结果比随机切分更有参考价值。切分代码很简单:

train = df.filter(df.timestamp < cutoff) test = df.filter(df.timestamp >= cutoff)

3.3 推荐结果的生成与评估指标

模型训练结束后,要生成每个用户的Top N推荐列表。这里有坑:如果直接把全部用户和物品喂给model.recommendForAllUsers(10),在集群上会产生剧烈的中间数据膨胀,一个小数据集都要跑半天。所以我会先通过SQL过滤出活跃用户(比如行为数大于5的用户),只对这批用户生成推荐,演示效果更好,也节省计算资源。

评估是决定推荐系统能不能落地的重要一步。我同时计算了多个指标,逐一解释:

  • RMSE和MAE:衡量预测评分与真实评分的偏差。RMSE:sqrt(mean((prediction - actual)^2)),MAE:mean(abs(prediction - actual))。前者对较大误差惩罚更重,更适合强调离群错误时使用。
  • 精确率Precision@K和召回率Recall@K:把评分大于等于4的图书定义为“用户真正喜欢的”,模型推荐的前K本书里,如果是“真正喜欢”的书就命中。精确率 = 命中数 / K,召回率 = 命中数 / 测试集中该用户喜欢的总书数。
  • 覆盖率:推荐列表中包含的图书数量占全量图书的比例。覆盖率太低说明推荐全都集中在热门书上,用户得到的推荐“视野”非常窄。

我跑出来的初始结果大致是:RMSE在0.82左右,Precision@10在0.18附近,Coverage在40%上下。这里的精确率看起来不高但实际上属于推荐领域的常态,因为测试集里的正样本本来就稀疏。如果你想知道调参方向,判断标准不是盲目追求单个指标,而是三个指标一起看。

3.4 混合推荐与冷启动策略

从算法层讲到这里,一个无法回避的问题是冷启动。我给系统加了三条经验策略。

新用户注册时没有行为数据,协同过滤无法给他推荐。我的处理是:注册流程中加入“感兴趣的图书分类”选择,默认状态下直接给用户推荐该分类下评分最高的图书;另一个兜底策略是推荐全站热度前50的图书榜单。热门榜我实现时没有用复杂的推荐算法,就是group by book_id统计行为数倒序排列,结果缓存到Redis,接口响应非常快。

新书入库时没有任何用户行为记录,协同过滤同样无法处理。我用的是基于内容的推荐:从书籍的类别、标签、简介关键词、出版社、作者这几个字段计算内容特征向量,然后与新书做余弦相似度,找出相似度最高的若干本书,把这本新书推荐给其相似书籍的所有读者。实际验证下来,这个方案对文学类和计算机类图书效果超过预期。

混合推荐的融合公式我最后采用的是加权线性组合:

final_score = 0.6 * als_score + 0.3 * itemcf_score + 0.1 * content_score

权重0.6、0.3、0.1是通过小规模实验人工调整出来的。如果你有时间,可以通过网格搜索在离线测试集上找最优权重,但作为毕设项目,手工调权配合简单的效果对比已经足够说明问题了。参与加权的三个分数必须先各自归一化到相同量纲,否则某个分数取值范围大就会主导结果,这一点很多同学会忽略。

4. 系统后端与前端模块实现

4.1 Spring Boot后端架构与接口设计

推荐模型只是引擎,用户还要能通过界面看到推荐结果。我后端采用Spring Boot 2.x框架,整个工程按标准三层结构拆分:Controller层负责接收请求,Service层负责业务处理,Mapper层操作数据库。

核心接口我设计了四个。第一个是热门榜单接口,返回全站热门图书Top N;第二个是基于用户ID的个性化推荐接口,先查Redis缓存,有缓存直接返回,没有则查MySQL里ALS预存的推荐结果表;第三个是“相似图书”接口,给用户展示某本书的关联推荐;第四个是评分提交接口,用户给图书打分后,数据写入MySQL并异步触发推荐结果更新。

有一个设计细节值得一提:为了在演示时能反映用户评分的变化,我把ALS的离线推荐结果和实时反馈分开存储。离线结果是凌晨批量任务生成的,存MySQL的recommend_result表;用户实时评分后,Redis缓存里对应Key会失效,下次请求时后端重新从MySQL读取并返回。这种设计兼顾了实时性的观感和系统的稳定性。

4.2 推荐引擎服务化与离线任务调度

推荐引擎怎么和Spring Boot结合?很多人在这里卡住。我采用的方案是:Spark训练和预测是独立的离线任务,运行完成后结果写入MySQL和Redis,Spring Boot只从数据库和缓存中读取结果,不直接调用Spark。这么做的好处是解耦——Spark任务重、耗时长,不能放在Web请求路径里,否则用户点一下等几十秒,体验直接崩塌。

离线任务的调度我用的是最简单的Linux cron。晚高峰之后跑一次全量任务,生成所有活跃用户的推荐结果。当时考虑过用Azkaban或Airflow这种专业的调度平台,但作为一个单人项目,引入它们带来的复杂度大于收益。生产环境在任务数量和依赖复杂度上来之后,一定要上调度框架,但学习阶段先用cron把逻辑跑通,日后再迁移即可。

Redis缓存使用比较简单,主要缓存两类数据:热门榜和个性化推荐结果。设置过期时间的方式是:热门榜过期时间1小时,个性化推荐结果24小时。这里要明确一点设计取舍:过期时间太长的话,用户下次登录看到的还是旧推荐,感觉系统“没反应”;太短的话,又频繁触发全量重新计算。最后一版取24小时,每天过期后由定时任务提前刷一遍缓存,保证白天用户访问时基本命中缓存。

4.3 前端可视化和交互设计

前端我用Vue 2 + Element UI搭的界面,视觉上以简洁展示为主。页面布局是:顶部分类导航栏,中部是“热门推荐”轮播区域,下面按推荐理由分组展示“为你推荐”图书列表。每本书展示封面、书名、作者、评分、推荐标签,用户点击进入详情页,可以看到相似图书推荐。

上述推荐理由也很有讲究。我给每本推荐图书生成了简单的推荐解释:如果是基于用户浏览过的某本书,页面会显示“因为你读过《XXX》,所以推荐这本书”;如果是基于协同过滤,就显示“和你口味相似的人也读过”。这种透明化推荐的展示,在用户体验上效果显著,也体现了对推荐逻辑的深入理解。

可视化部分我用了ECharts。首页上放了三个图:用户活跃度的分布图(横轴是用户行为数区间,纵轴是人数)、分类偏好分布图(用饼图展示用户最偏好的图书分类)、推荐覆盖率折线图。图表数据由后端聚合接口提供,前端只负责渲染。可视化的意义不只在于好看,还能帮助排查问题——比如分类偏好图异常时,往往意味着某一个分区的数据量有异常。

5. 常见问题与排查实录

5.1 评分矩阵稀疏与相似度计算失真

我遇到过最典型的问题是:ALS模型跑出来的推荐结果全部都是热门书。为什么会这样?因为评分矩阵稀疏,用户与物品的共现关系太少,模型学到的潜在因子偏向于物品的全局热度而不是用户个性化偏好。此时修改相似度计算的权重公式,或者在ALS中提高setRegParam、调小setRank会有改善,但最根本的办法是清理无效用户数据。我发现数据里有大量“僵尸用户”——只注册并产生了不到3条记录,这些数据对矩阵分解贡献的只有噪声。把行为数少于5条的用户过滤掉之后,覆盖率提升了接近15%。

另一个问题是相似度计算中的“大众脸”现象。比如《活着》这本书因为太有名,跟几乎所有其他书都会被算成相似,导致推荐大量混杂不相干图书。解决办法就是我在3.1节提到的热度惩罚项1 / log(1 + |N(u)|),对活跃度高用户的共现贡献进行降权,这个公式在工业界也是主流方案。

5.2 大数据环境下的性能瓶颈与数据倾斜

搭了三节点Hadoop集群跑任务时,性能问题几乎是不可避免的。最典型的是数据倾斜:某个热门书籍的评分记录特别多,导致按这个书ID进行聚合时,负责该key的Reduce任务卡到天荒地老,其他任务早就跑完了,整个Spark作业卡在最后几个task上。

我排查数据倾斜的方法很简单:看Spark UI上Task的Shuffle Read字节数。如果某个Task是其它Task的几十倍,基本就能确定倾斜落在哪个key上。处理办法是加盐:为热点key的每条记录拼一个随机数分成若干子key,聚合后再做一次去盐合并。以我的数据规模,加盐处理之后整个ETL作业耗时从25分钟降到8分钟,效果立竿见影。

还有一个更容易被忽视的性能问题:小文件过多。爬虫生成的数据是几千个小CSV文件分别写入HDFS,每个文件才几十KB。Hive读这些小文件时单单元调度开销极大。解决办法是把数据合并成少量大文件后再加载Hive表,并发参数设置也需要注意,能显著提升查询性能。

5.3 模块联调与前后端对接的坑

整个项目最容易出问题的地方反而不在算法,在前后端联调。我踩过的坑包括:后端返回的推荐结果字段是BigDecimal类型,结果JSON序列化后变成了科学计数法,前端拿到数据直接渲染错了格式;前端传的时间戳是毫秒单位,后端按秒解析,导致时间切分训练集和测试集时数据全部落入同一侧;前后端跨域问题在首次联调时基本必现,记得在后端配置CorsFilter。

这里我要强烈建议一个实践:为每个接口编写接口调试文档,至少包含请求参数、返回结构、错误码说明。不需要用什么专业工具,写到一个Markdown文档里就行。不要问,项目后来回看代码时就是靠这个文档把接口逻辑快速理清楚的。

5.4 问题排查速查表

现象可能原因排查方向解法
ALS输出全为NaN用户或物品ID未转换连续整数类型检测ID字段类型统一转为Int/Long类型
推荐结果全部是热门书评分矩阵过稀疏或正则化太小检查用户人均行为数过滤冷用户、增大regParam
Hive查询极慢小文件过多查看HDFS目录文件数合并小文件、使用ORC格式
Spark任务卡在最后几个Task数据倾斜Spark UI查看Task耗时分布热点key加盐
Redis缓存命中率几乎为0key过期策略设置不合理查看过期时间日志加过期时间抖动、提前预热
前端接口返回科学计数法数字类型序列化问题检查后端返回值类型转为字符串或设置精度格式

这些坑看着简单,但每一个都是真实消耗过时间的。把这些问题和解决办法整理进论文或项目文档的“问题与解决方案”章节,反而比算法原理部分更容易获得指导老师的认可,因为这说明你是真的把项目跑通了,而不是只有代码没有过程。

6. 写在最后:一些个人的经验体会

整套项目做下来,我最深的体会是:不要把推荐系统简单理解成一个算法模型,它是一个完整的数据工程产品。数据采集质量、数仓分层合理性、ETL任务的性能、接口设计是否友好、前端展示是否直观,任何一环掉链子,整个系统的表现都会大打折扣。最后分享一个容易被忽略的小技巧:模型评估阶段的对比实验一定要保留。把ItemCF、ALS、混合推荐三者的评估结果整理成图表,既能在论文里作为核心证据,也能在答辩时展示你具备“设计实验-实现-评估-迭代”完整能力。按照我个人经验,这部分花费的时间不会超过两个晚上,但对项目评价的提升非常显著。

如果你想把项目继续往下扩展,可以尝试接入Kafka和Flink做实时推荐,用户刚对一本书点了“想看”,几秒后刷新页面就能在推荐列表里看到类似书籍。这个扩展方向在架构上是顺理成章的,难度也可控。但先把离线推荐链路吃透,比什么都重要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询