ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Hadoop的电影推荐系统:伪分布式搭建与ALS协同过滤实战

基于Hadoop的电影推荐系统:伪分布式搭建与ALS协同过滤实战 简介这份资源是基于Hadoop框架构建的电影推荐系统完整项目包面向具备Java基础、希望实践大数据分布式计算与个性化推荐算法的开发者与学习者。项目以HDFS存储用户行为与评分数据通过MapReduce完成数据清洗、相似度计算与推荐生成并可能结合协同过滤、内容过滤等策略是理解大数据推荐链路的典型实例。压缩包共1117个文件约40.21MB涵盖379个php、169个html、157个png、122个js、60个css等前端与页面资源以及22个py脚本、sql、xml、json、yaml等配置与数据文件另含docx、pdf、mpp等文档便于梳理项目结构与部署流程。目前已有279人学习下载。读者可从中获取完整的推荐系统源码、Hadoop任务实现、前后端交互页面及配置参考适合用于课程设计、毕业设计或大数据入门实战帮助快速搭建可运行的电影推荐环境并理解分布式计算与推荐算法的结合方式。1. 基于 Hadoop 的电影推荐系统从零搭建到跑通协同过滤如果你手头正好有一个「基于 Hadoop 电影推荐系统.zip」这样的课程设计或练手项目大概率会经历三个阶段解压后一脸懵、照着 README 跑不起来、跑起来也不知道推荐结果是怎么算出来的。这个标题背后其实是一条很典型的大数据入门链路——用 Hadoop 的 HDFS 存电影评分数据用 MapReduce 或 Spark 做协同过滤计算最后把推荐结果落库或输出成文件。它解决的核心问题是当用户-物品评分矩阵大到单机内存放不下时怎么用分布式的方式算出「你可能还喜欢」。适合谁适合正在做 Hadoop 课程设计的学生、想从单机推荐算法过渡到分布式实现的工程师以及需要一套能写进简历的完整大数据项目的人。热搜里 hadoop 伪分布式搭建、hadoop 安装与配置、hadoop 集群搭建这些词说明大部分人卡在环境这一关所以这篇会先把环境讲透再讲算法落地。2. 环境选型与 Hadoop 伪分布式搭建单机也能跑通分布式逻辑2.1 为什么课程设计优先选伪分布式而不是全分布式很多人一上来就想搭三台虚拟机做全分布式结果光 SSH 免密和网络配置就耗掉两天最后算法一行没写。我的建议很明确课程设计和本地开发阶段一律先用伪分布式。伪分布式是在一台机器上启动 NameNode、DataNode、ResourceManager、NodeManager 全部守护进程数据照样走 HDFS任务照样走 YARN分布式该有的逻辑一个不少只是物理上在一台机器。等你把推荐算法跑通了再迁移到全分布式只需要改几个配置文件里的主机名代码一行不用动。选型上还有几个现实考量。Hadoop 版本建议用 3.x因为 2.x 在很多新系统上编译兼容性越来越差而 3.x 对 Java 版本要求是 JDK 8 或 11别用 JDK 17 以上否则会遇到一堆反射相关的报错。操作系统用 Ubuntu 20.04 或 CentOS 7 都行Windows 下用 IDEA 搭建 Hadoop 开发环境也可以但本地库需要额外处理 winutils新手容易在这里翻车所以能上 Linux 就上 Linux。2.2 伪分布式搭建的完整命令与配置下面这套步骤是我在干净 Ubuntu 上反复验证过的按顺序执行即可。先准备 Java 环境# 安装 JDK 8Hadoop 3.x 对 JDK 8 兼容性最稳 sudo apt update sudo apt install openjdk-8-jdk -y java -version # 输出应类似 openjdk version 1.8.0_xxx接着下载并解压 Hadoop。注意不要用太新的小版本3.3.x 系列足够稳定# 下载 Hadoop 3.3.6官网归档地址按需替换镜像 wget https://archive.apache.org/dist/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz tar -zxvf hadoop-3.3.6.tar.gz -C /opt mv /opt/hadoop-3.3.6 /opt/hadoop配置环境变量编辑~/.bashrc追加以下内容export HADOOP_HOME/opt/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export HDFS_NAMENODE_USERroot export HDFS_DATANODE_USERroot export HDFS_SECONDARYNAMENODE_USERroot export YARN_RESOURCEMANAGER_USERroot export YARN_NODEMANAGER_USERroot执行source ~/.bashrc生效。然后修改$HADOOP_HOME/etc/hadoop/下的几个核心文件。core-site.xml指定 HDFS 的默认文件系统和临时目录configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/opt/hadoop/data/tmp/value /property /configurationhdfs-site.xml设置副本数为 1因为伪分布式只有一个 DataNodeconfiguration property namedfs.replication/name value1/value /property property namedfs.namenode.name.dir/name value/opt/hadoop/data/namenode/value /property property namedfs.datanode.data.dir/name value/opt/hadoop/data/datanode/value /property /configurationmapred-site.xml指定 MapReduce 跑在 YARN 上yarn-site.xml配置 ResourceManager 主机和 NodeManager 的辅助服务!-- mapred-site.xml -- configuration property namemapreduce.framework.name/name valueyarn/value /property /configuration !-- yarn-site.xml -- configuration property nameyarn.resourcemanager.hostname/name valuelocalhost/value /property property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property /configuration还需要在hadoop-env.sh里显式指定 JAVA_HOME否则启动时可能找不到 Javaecho export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 $HADOOP_HOME/etc/hadoop/hadoop-env.sh格式化 HDFS 并启动hdfs namenode -format start-dfs.sh start-yarn.sh jpsjps应该看到 NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager 五个进程。少任何一个都说明配置有问题先去看$HADOOP_HOME/logs/下对应的日志。2.3 验证 HDFS 和 YARN 是否真的可用光看进程不够要实际跑一个任务。先建目录、传文件hdfs dfs -mkdir -p /user/root/input echo hello hadoop hello movie test.txt hdfs dfs -put test.txt /user/root/input/ hdfs dfs -cat /user/root/input/test.txt然后跑一个自带的 wordcount 示例验证 YARN 调度正常hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /user/root/input /user/root/output hdfs dfs -cat /user/root/output/part-r-00000能输出词频统计结果说明 HDFS 读写和 MapReduce on YARN 这条链路全通了。这一步别跳过后面推荐系统跑不起来时你至少能确定不是环境问题。3. 电影评分数据准备与 HDFS 存储把 MovieLens 灌进去3.1 数据集选择与字段说明电影推荐系统最常用的公开数据集是 MovieLens常见的有 ml-latest-small约 10 万条评分和 ml-1m约 100 万条评分。课程设计用 ml-latest-small 就够了数据量小、跑得快算法逻辑完全一样。核心文件是ratings.csv字段为 userId、movieId、rating、timestamp还有movies.csv包含 movieId、title、genres。选这个数据集的原因是它天然就是「用户-物品-评分」三元组协同过滤直接能用。别自己造数据造出来的分布不真实算出来的推荐结果没有参考价值。3.2 上传数据到 HDFS 并做初步清洗先把 ratings.csv 传到 HDFShdfs dfs -mkdir -p /movie/input hdfs dfs -put ratings.csv /movie/input/ hdfs dfs -ls /movie/input/实际数据里可能有缺失评分或重复记录用 MapReduce 或 Spark 做一次清洗。这里给一个 Spark 清洗的写法因为后面推荐算法也建议用 Spark比裸写 MapReduce 省事很多from pyspark.sql import SparkSession from pyspark.sql.functions import col spark SparkSession.builder \ .appName(MovieDataClean) \ .master(yarn) \ .getOrCreate() # 读取 HDFS 上的 CSV带表头 df spark.read.csv(hdfs://localhost:9000/movie/input/ratings.csv, headerTrue, inferSchemaTrue) # 去掉评分为空、超出 0.5-5.0 范围的记录并去重 clean df.filter((col(rating) 0.5) (col(rating) 5.0)) \ .dropDuplicates([userId, movieId]) # 写回 HDFSparquet 格式读取更快 clean.write.mode(overwrite).parquet(hdfs://localhost:9000/movie/clean) clean.show(5) spark.stop()这段代码的逻辑是读原始 CSV过滤掉异常评分按用户和电影去重最后以 parquet 格式写回。parquet 是列式存储后面做矩阵计算时读取效率比 CSV 高很多。参数上注意master(yarn)表示提交到 YARN本地调试时可以改成local[*]。3.3 数据分布检查别急着跑算法清洗完先看一眼数据分布这一步很多人跳过结果算法跑出来推荐全是烂片还不知道为什么# 统计每个用户的评分数量分布 user_counts clean.groupBy(userId).count() user_counts.describe().show() # 统计每部电影的评分数量 movie_counts clean.groupBy(movieId).count() movie_counts.orderBy(col(count).desc()).show(10)如果发现某些用户只有一两条评分或者某些电影只有一个人评过这些数据在协同过滤里基本是噪声。常见做法是设置阈值比如只保留评分次数大于 20 的电影和评分次数大于 50 的用户。阈值怎么定没有标准答案数据量大就设高一点数据量小就设低一点核心是保证用户-物品矩阵有足够的重叠。4. 协同过滤算法实现ALS 矩阵分解在 Spark 上怎么跑4.1 为什么选 ALS 而不是 UserCF/ItemCF协同过滤分两大类基于邻域的方法UserCF、ItemCF和基于模型的方法矩阵分解。UserCF 和 ItemCF 在数据量小的时候效果不错但计算相似度矩阵的复杂度是 O(n²)用户或物品一多就扛不住。ALS交替最小二乘是矩阵分解的代表算法把用户-物品评分矩阵分解成两个低维矩阵的乘积通过交替固定一个矩阵优化另一个来逼近原始评分。Spark MLlib 内置了 ALS 实现能直接跑在 YARN 上分布式训练这是课程设计里最省事也最能体现「分布式」价值的方案。选 ALS 还有一个现实原因它天然支持隐式反馈和正则化能缓解过拟合。你不需要自己手写梯度下降调几个参数就能出结果对新手友好。4.2 ALS 训练的完整代码与参数解释下面这段代码是推荐系统的核心直接可以在 Spark 上跑from pyspark.sql import SparkSession from pyspark.ml.recommendation import ALS from pyspark.ml.evaluation import RegressionEvaluator spark SparkSession.builder \ .appName(MovieALSRecommender) \ .master(yarn) \ .getOrCreate() # 读取清洗后的数据 ratings spark.read.parquet(hdfs://localhost:9000/movie/clean) # 按 8:2 划分训练集和测试集 (training, test) ratings.randomSplit([0.8, 0.2], seed42) # 构建 ALS 模型 als ALS( maxIter10, # 迭代次数一般 10-20 够用 regParam0.1, # 正则化系数防止过拟合 userColuserId, itemColmovieId, ratingColrating, coldStartStrategydrop, # 丢弃冷启动用户/物品的预测 nonnegativeTrue, # 评分非负加约束更合理 rank10 # 隐因子维度10-200 之间调 ) model als.fit(training) # 在测试集上预测 predictions model.transform(test) # 用 RMSE 评估 evaluator RegressionEvaluator( metricNamermse, labelColrating, predictionColprediction ) rmse evaluator.evaluate(predictions) print(Root-mean-square error str(rmse)) # 为每个用户生成 Top10 推荐 user_recs model.recommendForAllUsers(10) user_recs.show(5, truncateFalse) # 保存模型和推荐结果 model.save(hdfs://localhost:9000/movie/model) user_recs.write.mode(overwrite).parquet(hdfs://localhost:9000/movie/recs) spark.stop()逻辑说明先读 parquet 数据按 8:2 切分用训练集拟合 ALS 模型在测试集上算 RMSE 衡量预测误差最后给所有用户生成 Top10 推荐并保存。参数上rank是隐因子维度太小欠拟合、太大过拟合10 到 200 之间试regParam控制正则化强度0.01 到 1 之间调maxIter一般 10 到 20再多收益递减。coldStartStrategydrop很重要否则测试集里出现训练集没见过的用户或电影时预测值会是 NaNRMSE 直接算不出来。4.3 用 RMSE 和推荐样例判断模型好坏RMSE 是回归任务的常用指标值越小说明预测评分越接近真实评分。MovieLens small 数据集上ALS 的 RMSE 通常在 0.85 到 1.0 之间。如果 RMSE 大于 1.2说明模型没学好优先检查数据清洗是否到位、rank 是否太小、regParam 是否过大。如果 RMSE 小于 0.7反而要警惕可能是数据泄漏比如测试集混进了训练集。除了 RMSE还要肉眼看推荐结果。user_recs里每个用户对应一个推荐列表包含 movieId 和预测评分。把 movieId 关联回 movies.csv看看推荐的是不是合理。如果给一个爱看动画片的用户推荐了一堆恐怖片那模型肯定有问题可能是数据里用户评分太稀疏或者 rank 设得太低导致表达能力不足。5. 避坑与排查那些让推荐系统跑不起来的常见问题5.1 坑一HDFS 启动后 DataNode 起不来现象jps只看到 NameNode没有 DataNodehdfs dfsadmin -report显示没有可用节点。原因最常见的是hadoop.tmp.dir配置的目录权限不对或者多次hdfs namenode -format导致 clusterID 不一致。DataNode 启动时会校验自己的 clusterID 和 NameNode 是否匹配不匹配就直接退出。解决先停掉所有进程stop-dfs.sh删掉hadoop.tmp.dir下的所有数据重新格式化一次再启动。注意格式化只能做一次除非你清空了所有数据目录。另外确认dfs.datanode.data.dir目录存在且当前用户有写权限。5.2 坑二Spark 提交到 YARN 报内存不足现象任务提交后卡在 ACCEPTED 状态或者直接报Container killed by YARN for exceeding memory limits。原因YARN 默认给每个容器分配的内存比较小而 ALS 训练需要一定内存。另外spark.executor.memory和yarn.nodemanager.resource.memory-mb不匹配也会导致容器申请不到资源。解决提交时显式指定资源比如--executor-memory 2g --num-executors 2 --executor-cores 2同时确认yarn-site.xml里yarn.nodemanager.resource.memory-mb至少是 executor 内存的两倍。伪分布式下资源有限别把 executor 内存设得比物理内存还大。5.3 坑三ALS 预测结果全是 NaN现象predictions里 prediction 列全是 NaNRMSE 算出来也是 NaN。原因测试集里出现了训练集没有的用户或电影ALS 无法为这些冷启动对象生成隐因子默认返回 NaN。解决构建 ALS 时加coldStartStrategydrop让 Spark 自动丢弃这些无法预测的记录。如果不想丢可以改用coldStartStrategynan然后手动填充但课程设计里直接 drop 最简单。根本解决办法是划分数据集时保证每个用户和电影至少在训练集里出现一次可以用randomSplit后检查一下。5.4 坑四推荐结果全是同一个电影现象给所有用户生成的 Top10 推荐里排名第一的都是同一部电影。原因通常是数据分布极度不均某部电影被大量用户评了高分ALS 在训练时把它的隐因子学得特别「通用」导致对谁都推荐它。另外 regParam 太小、rank 太大也会加剧这个问题。解决先检查数据分布把评分次数过少的电影过滤掉同时考虑对热门电影做降权。参数上适当增大 regParam比如从 0.1 调到 0.2减小 rank比如从 50 降到 20。还可以在推荐时加多样性约束但课程设计里调参就够了。5.5 坑五Windows 下 IDEA 跑 Hadoop 报 winutils 错误现象在 Windows 上用 IDEA 跑 Spark 或 MapReduce报Could not locate executable null\bin\winutils.exe。原因Hadoop 的 Windows 原生库缺失Linux 下不需要Windows 下必须有 winutils.exe 和 hadoop.dll。解决下载对应 Hadoop 版本的 winutils放到HADOOP_HOME\bin下并在代码里设置System.setProperty(hadoop.home.dir, 你的HADOOP_HOME路径)。但说实话Windows 下跑 Hadoop 问题多能换 Linux 就换省下来的时间够你把算法调三轮。6. 从跑通到能演示推荐结果落库与 Top-N 调优技巧跑通 ALS 只是第一步课程设计要演示、要写报告你得把推荐结果变得「能看」。最直接的做法是把user_recs里的 movieId 关联回电影名输出成 CSV 或写进 MySQL。关联这一步用 Spark 的 join 就行movies spark.read.csv(hdfs://localhost:9000/movie/input/movies.csv, headerTrue, inferSchemaTrue) # user_recs 里 recommendations 是数组结构先 explode 展开 from pyspark.sql.functions import explode, col recs_flat user_recs.select(userId, explode(recommendations).alias(rec)) \ .select(userId, col(rec.movieId).alias(movieId), col(rec.rating).alias(score)) # 关联电影名 final recs_flat.join(movies, onmovieId, howleft) \ .select(userId, title, score) \ .orderBy(userId, col(score).desc()) final.write.mode(overwrite).csv(hdfs://localhost:9000/movie/final_recs, headerTrue)这段代码的关键是explode因为recommendForAllUsers返回的 recommendations 是一个数组不展开没法做 join。展开后按 movieId 关联 movies 表拿到电影名最后按用户和评分排序输出。参数上howleft保证即使某些 movieId 在 movies 表里缺失推荐记录也不会丢。Top-N 的 N 怎么定课程设计里 N10 是惯例但你可以做一个对比实验分别取 N5、10、20看推荐列表的覆盖率和多样性。覆盖率指推荐过的电影占总电影的比例多样性指推荐列表里不同 genres 的数量。N 太小用户选择少N 太大尾部推荐质量下降。我的经验是 N10 到 20 之间比较平衡具体看数据稀疏程度。还有一个容易被忽略的技巧对预测评分做归一化。ALS 输出的预测评分范围可能和真实评分范围不一致直接展示会让人困惑。可以按用户做 min-max 归一化把分数映射到 0 到 1 之间展示时更直观。另外如果想让推荐结果看起来更「新鲜」可以在排序时加一个时间衰减因子优先推荐近期评分多的电影但这属于进阶操作课程设计里不做也不影响。最后说一个我踩过的坑模型保存到 HDFS 后下次想加载回来做增量训练路径一定要写对而且 Spark 版本要一致否则反序列化会失败。我一般会在保存模型时同时导出一份推荐结果到本地演示的时候直接读本地 CSV不依赖集群避免现场翻车。这套方案从环境搭建到出结果熟练的话一天能跑通剩下的时间用来调参和写报告。希望帮到你。本文还有配套的精品资源点击获取
返回列表