尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于Hadoop的电影推荐系统毕业设计实战详解

基于Hadoop的电影推荐系统毕业设计实战详解 简介推荐系统是大数据领域最常见的应用方向之一其核心协同过滤算法通过分析用户历史行为挖掘物品间的潜在关联。在数据量增长时单机处理能力成为瓶颈分布式计算框架Hadoop凭借HDFS存储和MapReduce并行计算模型为大规模离线推荐任务提供了可靠方案。实际工程中常采用离线计算在线查询的架构利用Hadoop伪分布式环境完成相似度矩阵计算和预测评分将结果存入MySQL供业务端调用。这种模式广泛应用于电商、视频、音乐等内容平台。本文以电影推荐场景为例完整梳理了基于Hadoop的推荐系统实现路径涵盖数据预处理、算法落地、环境搭建及性能调优等关键环节为大数据方向的实践项目提供可复用的参考模板。 毕业设计做了个基于 Hadoop 的电影推荐系统从选题、架构设计、代码实现到踩坑修复完整走了一遍。这篇博客把整个项目拆开来讲包括核心算法怎么落地、伪分布式环境怎么搭、数据库表怎么设计、以及答辩时老师最爱问的几个问题给后面选类似题目的同学一个可以直接参考的模板。1. 为什么选“Hadoop 电影推荐”这个组合做毕业设计每年毕业设计选题季大数据方向的题目里“推荐系统”绝对是出现频率最高的关键词之一而“电影推荐”又是推荐系统里最好切入的场景。原因很简单电影数据容易获取、评分数据是标准的用户-物品二元关系、推荐效果可以用离线指标直观衡量。这个选题的组合逻辑是Hadoop 负责证明你掌握了分布式计算的基本功推荐系统负责证明你有算法落地的能力两个加在一起既有深度又有广度工作量也足够撑起一篇毕业论文。1.1 这个题目真正考察的能力点很多同学以为这个课题的核心是“写一个推荐算法”其实不是。导师真正想看的是三件事第一你能不能把一个大文件拆到多台机器上并行计算。这是 Hadoop 的基本功MapReduce 的 map 阶段和 reduce 阶段怎么划分、key 怎么设计、分区怎么控制这些细节比算法本身更能体现你的水平。第二你能不能把一个算法从数学公式变成可执行的代码。协同过滤的公式写在纸上是三行但真正跑起来会碰到数据倾斜、内存溢出、key 设计不合理导致结果错误等一堆问题。第三你能不能把 Hadoop 计算出来的结果和传统数据库衔接起来。这里涉及到 HDFS 和 MySQL 的交互、数据格式转换、结果表的设计等等单纯只写 Hadoop 程序是不完整的。1.2 选型时的几个备选方案对比我当初也考虑过其他组合列个表给你参考技术路线优点缺点Hadoop MapReduce 实现协同过滤逻辑清晰适合毕业设计展示答辩好讲代码量大迭代计算不方便Spark ALS 协同过滤实现简单性能好Spark MLlib 有现成库Spark 环境配置复杂算法“黑盒”感强答辩难深入Python Surprise 库纯离线实验代码最少没有分布式处理环节体现不了大数据知识点Storm/Flink 实时推荐技术新颖数据源难搞实时推荐在电影场景意义不大我的建议是毕业设计求“稳”选 Hadoop MapReduce 手工实现协同过滤虽然代码多一些但每一步都是你自己写的答辩的时候问到细节你都能答上来。2. 整体架构设计四个模块加一条数据流向项目的整体架构直接决定后面写代码的复杂度。我当时的架构分成四个模块数据采集与预处理、推荐计算引擎、数据存储层、前端展示层。2.1 数据流向的完整链路整个系统的数据流向是这样的用户行为数据(CSV) → HDFS存储 → MapReduce预处理(数据清洗) → 推荐算法MapReduce作业 → 结果写入MySQL → Web后端读取MySQL → 前端展示这套链路最核心的设计思想是Hadoop 集群负责离线计算MySQL 负责在线服务。推荐结果不是实时算出来的而是提前算好存到数据库里用户访问时直接查表返回。这种“离线计算 在线查询”的模式是工业界最常见的架构用在这里也完全合理。2.2 数据集的选择MovieLens 是最稳妥的选择电影推荐系统的数据集最常用的是 MovieLens明尼苏达大学 GroupLens 研究组发布的公开数据集。它有几个不同的规模版本100K10万条评分、1M100万条评分、10M1000万条评分、20M2000万条评分。毕业设计我建议直接用 1M 版本原因有三个100K 数据量太小跑 MapReduce 体现不出分布式计算的优势几秒钟就出结果了答辩时不好讲。1M 数据量在单机伪分布式环境下完全能跑执行时间几分钟到十几分钟既能展示 MapReduce 的过程又不会因为数据量太大导致作业一直跑不完。10M 以上的版本在单机伪分布式下会比较吃力如果集群资源不够reduce 阶段可能会非常慢。1M 版本包含的文件ratings.dat评分数据约100万条、users.dat用户数据、movies.dat电影数据。记得用 1M 版本的原始.dat文件而不是自己爬的数据答辩时你可以明确说明数据来源和格式可信度高很多。2.3 为什么最终选了 Item-based 协同过滤推荐算法的选型是答辩中最容易被追问的点你要能说清楚为什么选这个算法而不是其他算法。我最终实现的是基于物品的协同过滤Item-based Collaborative Filtering核心思想是给用户推荐与其过去喜欢的电影相似的电影。“相似”不是内容上的相似比如都是科幻片而是行为上的相似——即被同一批用户打过分或喜欢过的电影被认为是有相似性的。对比 User-based 协同过滤Item-based 有几个明显的优势第一推荐系统的核心痛点在于“物品数量通常远小于用户数量”物品之间的相似度矩阵计算量相对小而且可以离线预先算好。第二Item-based 推荐结果的可解释性强。页面可以展示“因为你看过《盗梦空间》所以推荐《星际穿越》”这类理由而 User-based 很难向用户解释为什么推荐某部电影。第三物品相似度相对稳定不用频繁更新。用户行为不断产生新数据用户的相似度变化很快而物品的相似度在短期内基本不会大变这让离线计算的可行性和可维护性大幅提升。所以这套系统的核心流程就是两阶段 MapReduce阶段一计算物品之间的共现矩阵和相似度矩阵。阶段二结合用户的历史评分加权求和算出用户对未看过的电影的预测评分。3. 推荐计算核心实现两个 MapReduce 作业撑起整套算法整个推荐系统的灵魂在 MapReduce 程序的设计上。我把代码拆分成两个作业串行执行第一个作业算相似度矩阵第二个作业算推荐结果。3.1 作业一物品相似度矩阵计算这个作业的输入是用户的评分数据一行格式为userID::movieID::rating::timestamp。Map 阶段的思路把同一个人看过的所有电影两两组合形成一条记录。比如用户 1 看过电影 A(5分)、B(3分)、C(4分)那 map 阶段就输出(A,B)、(A,C)、(B,C)。为什么是同现关系因为两个电影如果经常被同一个人观看并评分它们之间就有潜在关联。这是协同过滤最基础的假设。Map 输出的 key 是“电影对”value 是两个电影的评分组合。Reduce 阶段对每个电影对聚合统计两个电影同时被多少个用户看过共现次数同时计算它们之间的相似度。相似度计算公式我用的是余弦相似度similarity(A, B) sum(riA * riB) / (sqrt(sum(riA^2)) * sqrt(sum(riB^2)))其中 riA 是第 i 个用户对电影 A 的评分。在 Reduce 阶段我需要对每对电影累加用户评分的乘积和平方和。为了在同一个 Reduce 任务里拿到电影 A 和电影 B 的完整评分信息我设计了一个复合 key把电影对标记为(A,B)时同时考虑 A 的评分向量和 B 的评分向量。具体做法是在 Map 输出时对每个用户看过的电影列表两两组合输出(movieA, movieB, ratingA, ratingB)然后在 Reduce 里按 movieA-movieB 分组聚合算相似度。一个要注意的坑是两两组合会输出 n(n-1)/2 条记录如果某个用户看了 1000 部电影就是近 50 万对组合数据膨胀比较严重。MovieLens 1M 数据集跑下来这段中间数据会有几百万条但伪分布式模式下还能撑住。3.2 作业二预测评分生成推荐列表第二阶段利用第一阶段算出的相似度矩阵对每个用户生成推荐列表。Map 阶段输入用户评分记录 电影相似度表。这里我用了一个技巧把相似度表放在 Hadoop 的 DistributedCache 里Map 任务读取时直接加载到内存。Map 的逻辑是对每个用户看过的每部电影找出与该电影相似度最高的 K 部电影K 取 20然后输出(userID, candidateMovieID, 相似度*评分)。Reduce 阶段按 userID 分组对候选电影加权求和prediction(u, m) sum(similarity(m, n) * rating(u, n)) / sum(similarity(m, n))其中 n 是用户 u 看过的电影m 是候选电影。最后按预测分排序取 Top N 条写入结果。N 我配置的 10也就是每用户推荐 10 部电影。这个公式看着简单实际实现时有个容易翻车的点相似度矩阵是稠密的还是稀疏的。很多电影之间的相似度为 0不需要参与计算。我在代码里加了过滤相似度小于 0.1 的直接跳过减少很多无效计算。另外相似度的分母如果为 0即两部电影没有共同评分用户需要特殊处理否则会出现除零异常。3.3 代码结构上值得借鉴的分层设计如果你自己写代码建议按下面的包结构来组织cn.edu.recsys ├── mapreduce │ ├── CoOccurrenceMatrix.java // 作业一共现矩阵 │ ├── SimilarityMatrix.java // 作业一相似度计算可合并 │ ├── UserRatingVector.java // 作业二用户评分向量 │ └── RecommendJob.java // 作业二推荐结果生成 ├── dao │ ├── RatingDAO.java // 评分数据读取 │ └── RecommendResultDAO.java // 推荐结果落库 ├── util │ ├── MovieParser.java // 数据解析工具 │ └── SimilarityCalculator.java // 相似度计算公式 └── web ├── ReommendServlet.java └── MovieServlet.java这个结构的好处是 MapReduce 逻辑和 Web 展示逻辑完全解耦算归算、显示归显示调 bug 的时候定位问题很快。答辩的时候把包结构图放在 PPT 里给老师的印象就是思路清晰。4. 伪分布式环境搭建与常见的坑这个项目在真实集群上跑和伪分布式跑代码完全一样但环境的坑简直多到让人想砸电脑。我把我踩过的几个关键坑写出来你照着避雷就行。4.1 Hadoop 版本选型和配置要点我用的是 Hadoop 3.3.x 版本JDK 8。不推荐用 Hadoop 2.x 了3.x 的 hdfs 命令和 yarn 命令更规范而且默认端口、默认配置都有优化。伪分布式的核心配置就 5 个文件core-site.xml里设置fs.defaultFS为hdfs://localhost:9000hdfs-site.xml设置副本数dfs.replication为 1因为伪分布式只有一台机器副本数设多了反而报错yarn-site.xml配置资源管理还有mapred-site.xml指定用 YARN 调度。最容易踩的坑千万不要在 root 用户下直接跑 Hadoop会报mkdir: Cannot create directory /user/root或者权限错误。正确做法是创建一个专门的用户比如hadoop或者至少把 HDFS 的/user目录权限改对。我当时折腾了很久最后统一用hadoop用户操作就顺畅了。第二个坑伪分布式模式下每次重启系统NameNode 经常会进入 Safe Mode表现为Name node is in safe mode。这个不是故障是节点在启动时自动进入的保护状态。可以执行hdfs dfsadmin -safemode leave手动退出或者等它自动退出默认 30 秒。但如果你文件系统有问题它会一直卡在 safe mode这时要去检查/usr/local/hadoop/logs下的日志。4.2 ZooKeeper 整合到底需不需要标题里提到了“hadoop 和 zookeeper 整合实战”。这里我要说一个很多人搞混的概念如果你用的是 Hadoop 3.x 的单机伪分布式模式zookeeper 其实不是必须的。ZooKeeper 主要用在 HBase、Kafka 这些需要分布式协调的组件上或者 Hadoop 集群启用 HA高可用时才需要。那为什么题目里会带 zookeeper因为很多课程要求“hadoop 和 zookeeper 整合”或者你要在 Hadoop 之上再集成 HBase 来存数据那 ZooKeeper 就不能缺了。我当时的方案是HDFS 负责存储原始文件MySQL 负责存推荐结果中间本来用不到 ZooKeeper。但为了课程要求我把 ZooKeeper 装上了并让 HBase 也跑起来用 HBase 存了一部分中间结果。说实话实际效果提升有限但至少证明了你有能力整合多个分布式组件。如果只是做基于 Hadoop 的推荐系统ZooKeeper 不是硬性依赖。建议你在毕业论文里分清楚ZooKeeper 是分布式协调服务本系统中用于管理 HBase 的 Region Server 状态而不是推荐计算的主流程。这样老师觉得你有深度。4.3 伪分布式跑批的典型报错和处理方案# 启动服务 start-dfs.sh start-yarn.sh # 检查服务状态 jpsjps命令会输出 5 个进程才正常NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager。如果发现 DataNode 没起来90% 是dfs/data目录下残留了之前格式化时的 clusterID和 NameNode 的 clusterID 不一致。解决方案是删掉dfs/data和dfs/name目录重新执行hdfs namenode -format。再强调一次每次重新格式化之前一定记得先在 web 界面默认 9870 端口上确认数据不需要保留了因为格式化会清空所有 HDFS 上的数据。我第一次就这么干过辛辛苦苦导进去的数据全没了只能重新导入。4.4 小数据集跑不出分布式效果怎么办这个问题很实际。有些同学在伪分布式上跑了 100K 的数据集发现几秒就出结果完全看不到“分布式计算”的过程就以为系统没做好。其实要展示分布式效果有两个办法一是在日志里观察 Map 和 Reduce 的进度。YARN 的 web 界面8088 端口会显示每个作业的 Map 完成情况、Reduce 完成情况你可以截图放到论文里。二是用数据量说话。把 MovieLens 1M 的数据导进去观察作业执行时间、Shuffle 阶段的数据量这些指标都是实打实的。我当时跑完一个完整的推荐流程大概 15 分钟在日志里能看到大量的Map 100% Reduce 67%这类进度信息截图放在论文里很有说服力。注意如果你的机器内存只有 4G 或更小跑 1M 数据集可能会导致 YARN 容器内存溢出。需要在yarn-site.xml里调大内存参数或者限制容器内存。4G 内存的机器建议把yarn.nodemanager.resource.memory-mb调低到 2048。5. 数据库设计与数据落库的细节推荐系统算出来的结果最终要给人用就绕不开数据库。我用的 MySQL 5.7其实 8.0 也行但要注意驱动包的版本要匹配。5.1 核心表结构设计我设计了 5 张表分别是用户表、电影表、评分表、推荐结果表、用户行为日志表可选。-- 电影表 CREATE TABLE movies ( movie_id INT PRIMARY KEY, title VARCHAR(255), genres VARCHAR(255) ); -- 用户表 CREATE TABLE users ( user_id INT PRIMARY KEY, gender VARCHAR(10), age INT, occupation VARCHAR(50), zipcode VARCHAR(20) ); -- 评分表 CREATE TABLE ratings ( user_id INT, movie_id INT, rating DOUBLE, timestamp BIGINT, PRIMARY KEY (user_id, movie_id), INDEX idx_movie (movie_id) ); -- 推荐结果表 CREATE TABLE recommendations ( user_id INT, movie_id INT, predicted_rating DOUBLE, rank_num INT, PRIMARY KEY (user_id, movie_id), INDEX idx_user (user_id) );这里有几个设计要点值得说明评分表的主键必须是(user_id, movie_id)联合主键防止同一用户对同一电影的重复评分。建议加一个rank_num字段记录推荐序列中的位置业务侧直接ORDER BY rank_num就能取到 Top10不用每次都对predicted_rating排序性能好很多。recommendations表的数据量可能有几万行单表查询完全能扛住不需要做分区分表。如果后期数据量超出百万可以按user_id做 Hash 分表但这是后话。5.2 从 HDFS 结果到 MySQL 的导入方案MapReduce 作业输出的结果在 HDFS 里是文本文件通常是一个目录下有多个 part 文件。如何把这个目录里的文件导入 MySQL我当时试了三种方案方案一直接写一个 Java 程序读 HDFS 文件用 JDBC 批量插入。这个最稳可控制性强适合量不大几万条的场景。方案二把 HDFS 文件下载到本地用LOAD DATA LOCAL INFILE导入。这个最快但要注意 MySQL 的secure-file-priv限制有时候本地文件路径受限。方案三用 Sqoop 直接做 HDFS 到 MySQL 的导入。最正统的大数据工具但多引入一个组件配置起来又要折腾一阵子。我最终用的是方案一因为推荐结果就几万行用 JDBC 批量提交也很快而且代码写在项目里答辩时可以现场展示说服力更强。关于批量插入有个重要的性能优化用 JDBC 的PreparedStatement 批量提交每 1000 条执行一次executeBatch()比逐条插入快 10 倍以上。我第一次没做批量6 万条数据导了 20 多分钟加了批量之后 3 秒完成。5.3 评分归一化和可解释性处理结果集里算出来的预测评分是浮点数直接用会有两个问题。一是分数范围可能不在 1~5 之间推荐出来的电影显示 5.8 分很怪二是不方便做“推荐理由”展示。我的处理是对每部电影的推荐分数做 Min-Max 归一化映射到 1~5 分区间。然后根据 Top 1 相似电影的名称生成推荐理由类似“因为你看过《XXX》预测你也会喜欢《YYY》”。这个理由存在推荐结果表里页面展示的时候直接读取。答辩时这个点是加分项因为大部分同学只能展示推荐列表你能展示推荐理由说明你考虑了用户侧的实际体验。6. Web 展示层和前后端交互逻辑推荐系统算完不算完能展示出来才算一个完整的毕设。我没有搞特别花哨的页面用的 JSP Servlet 的传统方案虽然没有前后端分离那么时髦好用稳定而且答辩讲起来不复杂。6.1 页面功能设计整个系统就三个页面用户登录/注册页。电影列表页分页 按类型筛选。个人推荐页展示 Top10 推荐电影 推荐理由。为什么不做评分交互、评论功能因为要控制篇幅和工作量。加一个功能就多一套表、多一堆前后端代码而毕设的核心在 Hadoop 推荐算法Web 端做太重反而喧宾夺主。6.2 后端查询的关键 SQL个人推荐页的 SQL 非常简单这也是把推荐结果提前落库的好处SELECT r.predicted_rating, r.rank_num, m.title, m.genres FROM recommendations r JOIN movies m ON r.movie_id m.movie_id WHERE r.user_id ? ORDER BY r.rank_num LIMIT 10;在user_id上有索引这个查询毫秒级返回完全不需要缓存。如果做缓存可以用 Redis 存user:{id}:recsys的 keyTTL 设置一天。但作为毕设不引入 Redis 也没问题老师在答辩时问到“性能瓶颈在哪”你可以准确回答“推荐结果查询走索引性能瓶颈不在数据库而在离线计算阶段”。6.3 Tomcat 和 Hadoop 在同一台机器的资源冲突跑 Web 的时候遇到过一个问题Tomcat 默认占用 8080 端口而 YARN 的 ResourceManager 默认也占用 8088 端口。不冲突但很容易混淆。如果你启动 Tomcat 失败了先看 8080 是否被占用ResourceManager 是 8088别搞混。更大的问题是内存伪分布式的 Hadoop 已经吃了不少内存Tomcat 默认的-Xmx512m可能不够。我给 Tomcat 的catalina.sh加了JAVA_OPTS-Xms256m -Xmx768m避免频繁 Full GC 导致页面卡顿。7. 调优经历一次数据倾斜的完整排查过程这部分我要详细写一个真实踩坑案例。主推作业跑 1M 数据时最初需要 40 多分钟后来优化到 12 分钟主要解决的是数据倾斜和 shuffle 效率两个问题。7.1 问题现象作业运行时所有 Map 任务早就 100% 完成了但所有 Reduce 任务卡在 33%最后一个 Reduce 任务跑了将近 25 分钟。日志里大量出现GC overhead limit exceeded的错误。7.2 根因定位我把作业日志拉下来分析发现某个特定的电影比如《肖申克的救赎》被非常多的用户看过导致它在物品共现矩阵中对应的组合数量远超其他电影。在 Map 阶段做两两组合时这部热门电影相关的记录占了总记录量的很大比例并且集中发往同一个 Reduce 分区变成了典型的数据倾斜。7.3 优化方案两个手段结合第一对热门电影做降权处理。对于用户看过超过 500 次的电影在共现阶段降低其权重比如乘以 0.5。这不是“删除数据”而是让热门物品对相似度的影响不要过大对应到工业界就是 IDF 逆文档频率的思路。第二改造分区函数。默认的 HashPartitioner 按 key 的哈希值分区热门电影对大量集中在同一分区。我加了一个随机前缀的预分区策略如果某对电影涉及热门电影将 key 加一个随机后缀让数据分散到多个 Reduce。这一步需要把输出格式设计好保证分完再汇总。这个优化做完整个作业从 40 分钟降到 12 分钟效果显著。7.4 经验总结数据倾斜是 MapReduce 和 Spark 里最经典的问题。优化时记住一句话先定位分布再优化 shuffle不要一上来就调内存和并行度。只要数据分布不均匀盲目加资源只会让倾斜更严重。后来我在论文里专门写了一节“数据倾斜的检测与优化”配了优化前后的作业时间对比图这部分成了答辩时最有说服力的内容。8. 代码与部署清单提交之前要准备的东西临近提交代码和论文时整理了一份清单照着核对基本就不怕漏东西。8.1 项目代码清单Hadoop MapReduce 源码两个作业包含完整注释。数据预处理脚本将 MovieLens 的.dat文件转换为 Hadoop 作业能直接读取的格式。Web 端源码Servlet、JSP、JDBC 工具类。数据库初始化脚本init.sql建库、建表、导入基础数据。部署文档环境变量配置、Hadoop 启动步骤、作业提交命令、Tomcat 部署步骤。8.2 提交代码的几个注意事项第一数据文件不要打包进源码压缩包。MovieLens 1M 有几十 MB评审老师不会真的去跑你的数据。源码里保留数据说明文档README.md写明数据来源、格式、下载地址即可。第二代码里不要出现绝对路径。很多同学本地跑通直接用/home/xxx/...这样的路径写进了代码老师换一台机器跑就废了。正确做法是用conf配置文件统一管理路径。第三确保代码能在干净环境下跑通。我踩过一个大坑本地环境配好了各种环境变量跑得欢但换一台机器重装环境后发现某个类缺失编译错误。后来我把环境重现的步骤写成了 shell 脚本一步一键部署这部分写在部署文档里很加分。8.3 答辩时的现场演示脚本现场演示最怕翻车稳定的演示顺序是关键。建议提前准备一个演示脚本预留 5-8 分钟的操作路径启动 Hadoop执行start-dfs.sh和start-yarn.sh用jps展示 5 个 Java 进程。查看 HDFS输入hdfs dfs -ls /movielens展示数据文件已上传用hdfs fsck看块信息。提交推荐作业执行打包好的一键提交脚本打开 YARN 的 8088 界面展示作业进度。打开 MySQL展示推荐结果表的数据量比如SELECT COUNT(*) FROM recommendations。启动 Tomcat登录页面、输入一个用户 ID、展示推荐的 10 部电影。整套流程控制在 5 到 8 分钟每个环节都提前跑通尽量练到不需要看笔记也能操作。提醒现场演示前一定要先确认recommendations表里已经有数据。我就见过有同学演示到一半发现忘了跑作业表是空的页面白屏当场社死。9. 答辩高频问题与回答思路最后说几个我在答辩时被问到最多的问题以及我是怎么答的为什么要用 Hadoop数据量真的够大吗这是一个经典的“灵魂拷问”也是最容易被老师追问的点。我的回答分两层第一从工程角度讲MapReduce 分布式框架具备横向扩展的能力数据集从 1M 扩展到 10M、100M 时通过增加节点数量来维持计算性能这是单机内存算法无法比拟的第二从学习价值讲本项目的核心目标在于掌握分布式计算框架的思维方式和实现细节而 MovieLens 1M 只是验证可行性的最小数据集。为什么选择协同过滤而不是基于内容的推荐协同过滤不需要物品的内容特征如导演、演员、类型只依赖用户历史行为避免了内容特征提取和特征工程的处理。在电影数据集上协同过滤的效果在实践中通常好于基于内容的方法因为它能发现用户自己都没意识到的跨类型关联。相似度计算为什么不用皮尔逊相关系数我选了余弦相似度。皮尔逊相关系数在用户评分数据稀疏时容易出问题两个电影如果只有一个人评分皮尔逊相关系数可能算出 1 或者 -1 的极端值导致推荐结果异常。余弦相似度在稀疏矩阵下表现更稳定而且计算简单适合 MapReduce 的批量处理。这个系统是实时的吗不是这是离线推荐系统定期比如每天运行一次生成新的推荐结果。如果要做实时的需要引入流计算框架如 Flink而结合在线实时计算时需要把物品相似度矩阵加载到内存再对用户最新行为进行实时增量计算。作业的执行时间瓶颈在哪主要在于相似度矩阵的计算规模即物品共现矩阵的生成和聚合数据量大时 shuffle 阶段 I/O 开销最大。通过预分区和降权优化可显著提升性能。这些问题的答案建议在写论文时同步整理成一个“答辩自问自答清单”既能在写论文时理清思路拿到论文终稿时再对照清单查漏补缺答辩自然就稳了。最后想说的几个实操体会整个项目做下来最深的感受是毕业设计的技术难点其实不在“新”而在“细”。协同过滤是 90 年代的算法Hadoop 是十几年前的技术但把它们组合起来并真正跑通中间涉及的工程细节远比想象得多。如果让我重新做一次我会在前期先花两天时间把所有环境问题跑通再开始写代码。很多人一开始先把代码写完了然后配环境时发现各种问题加班调试环境到崩溃其实环境优先级更高。另外代码里多写注释特别是 MapReduce 的 key、value 设计意图否则一个月后再看自己写的代码都会陌生。希望这篇分享能帮到正在准备这个题目的你。项目代码不复杂环境搭建却有不少暗坑照着上面的步骤走能省不少时间。真正动手做一遍你会理解“分布式计算”远不止跑通一个 WordCount 那么简单。本文还有配套的精品资源点击获取
返回列表