课程设计题目:基于Hadoop的电影评分数据分析与推荐系统
项目背景与意义
随着互联网和大数据技术的发展,电影行业产生了海量的用户评分、评论和观看记录数据,这些数据蕴含着巨大的商业价值,可以帮助电影公司了解用户偏好、预测票房、优化营销策略,并能为用户提供个性化的电影推荐。
传统的关系型数据库在处理这种PB级别的海量数据时,面临着I/O瓶颈、扩展性差和计算成本高等问题,Hadoop作为大数据领域的核心框架,以其分布式存储和分布式计算的能力,为处理和分析此类海量数据提供了理想的解决方案。

本项目旨在利用Hadoop生态系统,设计并实现一个电影评分数据分析系统,通过分析用户的历史评分数据,挖掘出有价值的统计信息,并构建一个简单的基于用户协同过滤的电影推荐模型,以验证Hadoop在处理实际大数据问题上的强大能力。
项目目标
- 数据获取与预处理: 获取公开的电影评分数据集(如MovieLens),并利用Hadoop进行数据清洗和预处理,将其转换为适合分析的格式。
- 数据分析与统计:
- 计算每部电影的平均评分和评分次数,并找出Top N高分电影。
- 统计每个用户的评分次数,并找出最活跃的Top N用户。
- 分析评分的分布情况(1-5星评分的占比)。
- 推荐算法实现:
- 实现一个基于用户的协同过滤推荐算法。
- 为指定用户推荐他可能感兴趣但尚未评分的电影。
- 系统验证与评估:
- 对数据分析结果进行验证,确保其正确性。
- 对推荐结果进行定性分析,评估推荐质量。
- 文档撰写: 完成一份详细的课程设计报告,包括需求分析、系统设计、实现过程、测试结果和总结反思。
技术选型与环境搭建
-
核心框架:
- Hadoop 3.x: 作为底层分布式文件系统和计算框架。
- HDFS (Hadoop Distributed File System): 用于存储原始数据、中间数据和最终结果。
- MapReduce: 用于编写并行处理程序,完成数据清洗、统计分析和推荐算法的核心计算。
- (可选) YARN (Yet Another Resource Negotiator): 作为集群的资源管理器。
-
开发语言: Java,因为Hadoop生态原生支持Java,API成熟稳定。
-
开发环境:

- 操作系统: Linux (推荐Ubuntu或CentOS)
- Java Development Kit (JDK): JDK 8或更高版本
- Hadoop安装包: 官方稳定版
- 构建工具: Maven (用于管理项目依赖)
- IDE: IntelliJ IDEA 或 Eclipse
-
测试数据集:
- MovieLens 100K Dataset: 包含约10万个评分,数据量小,适合快速开发和测试。
- MovieLens 1M/10M Dataset: 数据量更大,更能体现Hadoop的优势。
系统设计与实现
数据格式与HDFS存储
- 数据格式: MovieLens数据集通常是CSV或类似格式。
user_id, movie_id, rating, timestamp - HDFS存储: 将原始数据文件上传到HDFS的指定目录,如
/input/ml-100k/u.data。
数据预处理
- 目标: 清理无效数据(如缺失值、异常值),并转换为后续分析所需的格式。
- 实现: 编写一个MapReduce作业。
- Mapper:
- 读取每一行数据。
- 进行简单的校验(如rating是否在1-5之间)。
- 输出
<user_id, movie_id, rating>。
- Reducer (可选): 此阶段Reducer可以是一个“Identity Reducer”(即不做任何聚合),仅用于将Mapper的输出格式化并写入HDFS的
/cleaned_data目录。
- Mapper:
数据分析模块
计算电影平均评分和评分次数
- 目标: 输出每个电影的平均评分和总评分次数。
- 实现: 编写一个MapReduce作业。
- Mapper:
- 输入:
<user_id, movie_id, rating> - 输出:
<movie_id, (rating, 1)>
- 输入:
- Reducer:
- 输入:
<movie_id, [(rating1, 1), (rating2, 1), ...]> - 计算:总评分 = Σ rating,总次数 = Σ 1。
- 输出:
<movie_id, (average_rating, total_count)>
- 输入:
- Mapper:
找出Top 10高分电影
- 目标: 在任务一的基础上,按平均评分降序排序,并取前10名。
- 实现:
- 使用任务一的作业结果作为输入。
- 编写一个MapReduce作业进行二次排序。
- Mapper:
- 输入:
<movie_id, (average_rating, total_count)> - 输出:
<null, (average_rating, movie_id, total_count)>,将平均评分作为Key,以便全局排序。
- 输入:
- Reducer:
- Hadoop框架会自动按Key(平均评分)降序排序。
- Reducer按顺序接收数据,计数器从1开始,当计数器大于10时停止处理。
- 输出:
<rank, movie_id, average_rating, total_count>
- Mapper:
统计用户评分次数

- 目标: 找出评分最多的Top 10活跃用户。
- 实现: 类似任务二,但统计的是每个用户的出现次数。
- Mapper: 输出
<user_id, 1> - Reducer: 输出
<user_id, total_count> - 二次排序作业: 按总计数降序排序,取前10名。
- Mapper: 输出
推荐算法模块
算法:基于用户的协同过滤
-
核心思想: 找到与目标用户品味相似的“邻居”用户,然后将这些邻居用户喜欢但目标用户未接触过的物品推荐给目标用户。
-
实现步骤(使用MapReduce):
第一步:计算用户相似度(余弦相似度)
- 目标: 计算任意两个用户之间的相似度。
- 实现:
- Mapper 1 (构建用户-电影倒排表):
- 输入:
<user_id, movie_id, rating> - 输出:
<movie_id, (user_id, rating)>
- 输入:
- Reducer 1 (生成共现用户对):
- 输入:
<movie_id, [(user_id1, rating1), (user_id2, rating2), ...]> - 输出:对于同一部电影下的任意两个用户
(user_i, user_j),输出<user_i, user_j>和<user_j, user_i>(确保双向),可以附带一些信息,如共同电影数量。
- 输入:
- Mapper 2 (准备向量点积数据):
- 输入:
<user_i, user_j> - 输出:
<user_i, (user_j, 1)>和<user_j, (user_i, 1)>,这只是为了后续连接。 - (更优化的做法是:在Reducer 1中直接计算向量点积和模长,但逻辑复杂,一种更清晰但可能效率稍低的方法是使用多个Job连接评分数据)
- 输入:
- Reducer 2 (计算最终相似度):
这个步骤比较复杂,通常需要连接用户-电影评分表和共现用户对表来计算向量点积和模长,可以简化处理,只计算共同评分电影的数量作为相似度的度量(Jaccard相似度),或者使用更复杂的“连接-聚合”策略。
- Mapper 1 (构建用户-电影倒排表):
第二步:生成推荐列表
- 目标: 为指定用户User A,推荐他可能喜欢的电影。
- 实现:
- Mapper:
- 输入:
<user_i, user_j, similarity> - 输出:对于User A的邻居User_j,输出
<movie_id_rated_by_j, (similarity, user_j)>。
- 输入:
- Reducer (聚合与排序):
输入:
- Mapper: