直接说结论:如果你正愁毕业设计、课程设计或者项目实训缺一个有技术含量、又能完整跑起来的案例,这套“大数据驱动的在线教育平台智能推荐系统”是个相当不错的切入点。我拿到源码之后完整跑了一遍,又把核心模块翻了一遍,这篇文章直接把整个项目的设计思路、技术选型、推荐算法细节、大数据处理链路、源码结构和部署坑位全拆开讲清楚。不管你是想直接拿去用,还是想弄懂推荐系统和大数据到底怎么结合,都能省下不少时间。
先说这个项目是干什么的。它本质上是一个在线教育平台,用户在平台上浏览课程、收藏课程、学习视频,系统会记录这些行为数据,然后通过大数据处理流程做用户画像和课程画像,最后用推荐算法把用户可能感兴趣的课程推给他。典型的“数据采集 -> 数据清洗 -> 特征工程 -> 算法推荐 -> 结果展示”全链路。比那种只在前端写个静态页面的课设项目高出一个档次,又比纯算法调参的项目多了完整的业务场景和工程落地,作为学习案例很合适。
我花了一个周末的时间,把源码从下载到部署到二次修改完整走了一遍,下面全是实操过程中的真实记录。
1. 项目定位与设计思路拆解
1.1 这类系统想解决的真实问题
在线教育平台最常见的痛点就是课程太多、用户不知道学什么。你去慕课、网易云课堂这类平台,课程栏目动辄几十个分类、上万门课,用户打开首页如果没有好的推荐位,很容易迷失,然后直接关掉页面。所以推荐系统的核心价值就是两个词:降噪和转化。降噪指帮用户快速过滤不感兴趣的内容,转化指把用户可能感兴趣的课程推到面前,提高点击率和学习完成率。
这套源码解决的问题很实在:用数据代替人工运营去判断“该给谁推什么课”。传统做法是运营人员手动把优质课程放到首页,这种方式的问题是不能针对每个用户做差异化展示;而通过用户的历史行为数据,系统能给每个用户生成一套专属课程列表。同样是首页推荐位,张三看到的是Python进阶,李四看到的是数据分析实战,这才是智能推荐的意义。
1.2 设计目标与功能边界
这套系统的功能边界清晰,没有那种为了凑功能硬加模块的毛病。核心功能分为四大块:
- 用户管理:注册、登录、个人信息维护,支撑后面用户画像的构建。
- 课程管理:课程分类、课程信息管理、课程列表展示,管理员可以维护课程数据。
- 行为采集:记录用户浏览、收藏、学习、评分等行为,这是整个推荐系统的数据来源。
- 智能推荐:基于用户行为数据,通过协同过滤和基于内容的算法给用户生成个性化推荐列表。
这四块合在一起就构成了一个完整的闭环:用户产生行为 -> 行为被采集入库 -> 数据分析生成画像 -> 推荐算法计算 -> 结果展示给用户 -> 用户继续产生行为。这个闭环是大数据推荐系统和普通CRUD项目最本质的区别,也是这个项目最值得学习的地方。
1.3 为什么这个方案值得参考
我说几个很现实的原因。第一,技术栈覆盖面广,既有Spring Boot做后端开发,又有Hadoop生态做大数据存储和处理,还有协同过滤算法做推荐计算,一个项目把Java后端、大数据、机器学习三个方向都沾上了,这在简历上很好写。第二,业务场景真实,在线教育本身就是热门领域,推荐系统又是大数据方向的核心应用,面试时拿出来聊,面试官容易产生共鸣。第三,代码结构清晰,模块之间低耦合,想替换某个算法只需要改一个实现类,这种设计方式本身就是加分项。
2. 核心技术栈选型分析
2.1 后端框架层面的选择逻辑
这套系统的后端基础采用Spring Boot,这个选择没什么好纠结的,它就是当前Java后端的主流标准。Spring Boot最大的优势是简化了项目配置,内嵌Tomcat,打成一个jar包就能跑,非常适合课程设计和快速原型开发。同时Spring Boot的生态极其丰富,Spring MVC做接口、Spring Data JPA或MyBatis做数据访问、Spring Security或Shiro做权限控制,所有需要的组件都能无缝集成。
我看了源码里的代码结构,Controller层、Service层、DAO层分层很清楚,典型的教科书式分层架构。这种分层方式在教学场景下反而是优点,因为每个层次的职责一目了然,你照着学能建立很好的工程化思维。
2.2 大数据处理环节的技术选型
既然标题里挂着“大数据驱动”,那数据处理环节肯定不能只是用MySQL查一查就完事。这套系统在数据层用了Hadoop生态的组件。HDFS负责存储海量行为日志,MapReduce或者Spark负责对日志进行离线批量处理,计算用户和课程的偏好特征。
这里说句公道话,真实互联网公司的推荐系统确实用的是这套东西:日志进Kafka,实时流用Flink或Spark Streaming算,离线用Spark或MapReduce算,统一存储到Hive或ClickHouse。这套系统虽然简化了,但骨架是对得上的。用Hadoop生态来做,一方面是贴合“大数据”这个项目定位,另一方面是让你在实践中理解分布式计算的思维模式——数据太大单机装不下,就要分而治之,把任务拆成多个子任务并行处理。
2.3 数据库选型与数据分层存储
我打开源码里的配置文件,发现了多数据源的配置。MySQL存业务数据,比如用户表、课程表、订单表;HDFS或Hive存日志数据和计算中间结果。这种设计是有讲究的:业务数据要求强一致性和快速响应,MySQL这种关系型数据库最合适;而日志数据量大、结构松散、主要是追加写,用分布式文件系统更经济也更好扩展。
在实际部署的时候需要注意,如果你电脑内存只有8G,Hadoop集群建议只搭伪分布式模式,跑通流程就好。我在16G内存的机器上开了三个虚拟机做完全分布式,光系统资源就占了七八成,再做推荐计算直接卡死,后来换回伪分布式反而跑得很顺畅。课程设计这种场景,跑通流程比模拟真实集群更重要,别在环境上死磕。
3. 推荐算法核心逻辑剖析
3.1 协同过滤推荐算法精讲
这套系统的推荐算法核心是协同过滤,这是推荐系统领域最经典、应用最广泛的算法。协同过滤的核心思想用一个生活类比就能讲明白:你看电影的时候,如果发现某个朋友跟你口味很像,他推荐的电影你大概率也喜欢。系统做的事情就是把这个过程自动化——找到与你兴趣相似的用户群体,看看他们喜欢什么,把那些你喜欢的人喜欢但你还没看过的内容推荐给你。
具体到数学实现,分成两步。第一步是构建“用户-课程”评分矩阵,矩阵的行是用户,列是课程,值是用户对课程的评分或隐式反馈(浏览、点击、收藏等);第二步是计算用户之间的相似度,常用的有皮尔逊相关系数、余弦相似度。以余弦相似度为例,用户A和用户B的相似度计算公式是:
similarity(A, B) = (A向量 · B向量) / (|A向量| * |B向量|)其中A向量和B向量分别是用户对所有课程的评分向量,点积除以模长乘积,得到的结果在-1到1之间,越接近1表示越相似。
我特意去看了一下源码里这个算法的实现,发现它用的是基于物品的协同过滤(ItemCF),而不是基于用户的协同过滤(UserCF)。这个选择很专业,因为在线教育平台上用户数量远大于课程数量,物品的相似度矩阵比用户的相似度矩阵小得多,计算和存储成本更低。同时课程的属性相对稳定,不像用户的兴趣那样容易漂移,物品相似度可以离线计算然后定期更新,实时推荐时直接查结果就行。
3.2 基于内容的推荐作为补充
只有协同过滤是不够的,它有一个致命的先天缺陷——冷启动问题。新用户没有任何行为数据,系统无法计算他跟谁的相似度;新课程也没有任何用户行为,系统无法判断该推给谁。针对这个问题,源码里还实现了基于内容的推荐算法作为补充。
基于内容的推荐思路是:分析课程本身的属性(分类、标签、难度、讲师),构建课程的特征向量,然后和用户的偏好特征向量做匹配。用户在注册的时候可以填写感兴趣的方向,比如选择“Java”、“大数据”、“前端”,系统就把这些标签作为用户的初始偏好。新课程入库时打上标签,只要标签跟用户偏好匹配,就能推出去。
这个方案结合了两种算法的优势:协同过滤擅长挖掘潜在兴趣,基于内容擅长解决冷启动。我在实际运行测试时发现,新注册一个账号,填了“Python”偏好,推荐列表里就能立刻出现Python相关的课程,这说明基于内容的推荐确实在起作用;而老用户看了几节大数据课程之后,推荐列表里逐渐出现了相关的Spark、Flink课程,这是协同过滤在发挥作用。
3.3 推荐结果的排序与TopN截断
算法计算完之后不能原样输出,还需要做结果处理。源码里对推荐结果做了两件事:过滤和排序。过滤是把用户已经学过的、已经收藏的课程移除,避免重复推荐;排序是按照预测评分降序排列,取前N个作为最终的推荐列表。这个N在实际系统中是个超参数,源码里默认取10,也就是给每个用户推荐10门课。
这里的评分预测用了一个很经典的公式:
预测评分 = 用户对所有课程的平均评分 + 求和(物品相似度 * (用户对该物品的评分 - 该物品的平均评分)) / 求和(物品相似度)这是ItemCF的标准预测公式,说白了就是看用户历史喜欢的课程跟候选课程有多像,再把相似度加权求和。源码里面对这个公式的实现没有偷工减料,Maven依赖里有Apache Commons Math,底层用的矩阵运算库,在线性代数这块处理得挺规范。
4. 大数据处理链路与用户画像构建
4.1 数据采集与预处理流程
推荐系统的数据质量决定了推荐效果的上限。这套系统在数据采集上设计了两个入口:前端埋点上报后端接口,后端把用户行为日志异步写入日志文件;另一部分是直接从数据库同步业务数据。日志文件攒到一定规模后,由Hadoop的定时任务做批量导入。
我看了源码里的日志采集代码,发现行为数据包含这几个核心字段:用户ID、课程ID、行为类型(浏览、收藏、学习、评分)、行为时间、停留时长。这些都是推荐算法最核心的输入特征。说说我自己的经验,停留时长这个字段非常关键,用户可能只是点进去看一眼就关掉,也可能看了十分钟认真学完,这两种行为的权重完全不一样。
预处理阶段做的事情主要是三类:一是清洗,把字段缺失的记录补默认值或直接扔掉;二是去重,同一用户同一课程一天内重复浏览只算一次强行为或多次弱行为;三是转换格式,把日志转成Hive表能直接查询的结构化数据。预处理做完的数据才能进入特征计算环节。
4.2 用户画像与课程画像的构建方法
用户画像就是给用户打标签。这套系统的画像维度有这些:
| 画像维度 | 数据来源 | 计算方式 |
|---|---|---|
| 基础属性 | 注册信息 | 直接使用 |
| 兴趣偏好 | 选择标签 + 行为数据 | 加权计算 |
| 活跃度 | 登录频率、学习时长 | 时间衰减统计 |
| 学习进度 | 课程学习记录 | 最新状态同步 |
在实现层面,用户对每个课程分类的偏好分是这样算的:不同的行为类型有不同的权重系数,比如完整学习一门课的权重是10分,收藏是5分,仅浏览是1分;同时引入时间衰减因子,一周前的行为权重降低到当前的0.7,这样能保证画像反映的是用户近期的兴趣变化,而不是停留在三个月前的状态。
课程画像相对简单一些,核心是课程本身的分类、标签和难度等级。我在源码里看到课程表已经预置了一批打好了标签的课程数据,包括Java基础、Python数据分析、前端开发、大数据原理等热门分类,这些数据是推荐算法跑起来的基础。如果你要换自己的数据集,一定要把课程标签维护好,标签质量直接决定推荐效果。
4.3 离线计算与在线服务的配合
这套系统的时间线设计是:离线计算在每天凌晨定时跑一次,任务是处理前一天积累的行为日志,更新用户画像和课程相似度矩阵,生成每个用户的候选推荐集合并存入数据库;在线服务在用户访问页面时,直接从数据库读取该用户的推荐列表,做实时过滤后展示。
我之前带过几个学生复现类似项目,他们容易把实时推荐和离线推荐混在一起。这里要理解,真正的实时推荐系统(比如你刷新一下页面推荐就变了)需要Flink、Kafka这类流式计算框架,复杂度会成倍上升。这个项目的定位是用离线计算解决推荐问题,它已经足够完成“数据驱动推荐”的课题要求了。在代码里,离线任务和Web服务是分开的两个模块,互不干扰,这也是一个很值得学习的架构设计思路。
5. 系统核心模块与源码结构解析
5.1 源码工程的整体目录结构
先把目录结构摆出来:
online-education-recommend/ ├── admin/ # 后台管理模块 │ ├── controller/ # 管理端接口 │ └── service/ # 管理端业务逻辑 ├── portal/ # 前台门户模块 │ ├── controller/ # 用户端接口 │ └── service/ # 用户端业务逻辑 ├── recommend/ # 推荐算法模块 │ ├── collaborative/ # 协同过滤实现 │ ├── content-based/ # 基于内容推荐实现 │ └── model/ # 推荐模型实体类 ├── bigdata/ # 大数据处理模块 │ ├── mapreduce/ # MR离线计算任务 │ └── etl/ # 数据清洗转换任务 ├── common/ # 公共工具模块 ├── sql/ # 数据库初始化脚本 └── resources/ # 配置文件这个目录拆分得很讲究。推荐算法模块是独立存在的,不依赖Web层的Controller和Service,这意味着你把推荐模块单独拿出来用,或者想换成别的推荐算法,都不需要动其他模块。大数据处理模块也是独立工程,Maven里配置了Hadoop相关依赖,单独打包成jar提交到集群执行。
5.2 核心接口调用链路
从用户请求到推荐结果返回,一条完整的调用链路长这样:
用户打开首页 -> 请求/recommend/list接口 -> RecommendController接收请求 -> RecommendService调用UserPortraitService获取用户画像 -> 调用CollaborativeFilteringService获取协同过滤候选集 -> 调用ContentBasedService获取内容推荐候选集 -> 合并候选集 -> 去重过滤已学课程 -> 按评分排序 -> 取TopN -> 返回课程列表 -> 前端渲染展示这个链路里最有价值的设计是候选集合并。协同过滤和基于内容的推荐各算出一批候选课程,但两批课程可能会有重合,而且权重体系不同。源码里的合并策略是针对同一门课程,取两种算法评分的最大值作为最终评分;如果是不同课程,则按各自的算法权重排序后交替插入,保证推荐列表的多样性。这么做是防止永远只推同一类课程,让用户有新鲜感。
5.3 关键源码片段解读
我摘几段核心代码来说说实现细节。用户相似度计算这块,源码里是这么写的:
public double cosineSimilarity(Map<Long, Double> userRatings1, Map<Long, Double> userRatings2) { Set<Long> commonItems = new HashSet<>(userRatings1.keySet()); commonItems.retainAll(userRatings2.keySet()); if (commonItems.isEmpty()) { return 0.0; } double dotProduct = 0.0; double norm1 = 0.0; double norm2 = 0.0; for (Map.Entry<Long, Double> entry : userRatings1.entrySet()) { norm1 += Math.pow(entry.getValue(), 2); } for (Map.Entry<Long, Double> entry : userRatings2.entrySet()) { norm2 += Math.pow(entry.getValue(), 2); } for (Long itemId : commonItems) { dotProduct += userRatings1.get(itemId) * userRatings2.get(itemId); } return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)); }这段代码的逻辑很清楚:先取两个用户共同评分过的课程集合,如果没有共同课程直接返回0,说明这两个用户没有相似度基础;然后分别计算两个评分向量的模长,再计算共同课程的评分点积,最后点积除以模长乘积就是余弦相似度。这个实现的时间复杂度是O(n),n是用户评分课程数,在课程规模不大的时候性能足够。
物品相似度矩阵的离线计算代码也在recommend模块里,用的是同样的余弦相似度逻辑,只不过维度和方向变了。每次用户对课程产生新的行为,就会触发一次增量更新,把与该课程相关的相似度分数重算一遍。当然,这种增量更新的方式在数据量特别大的时候效率不够高,一个更工程化的方案是定期用Spark批量重算整个相似度矩阵,但作为课程设计已经够用了。
5.4 管理后台与前台门户的功能划分
管理后台这部分包含课程管理和用户管理两个核心页面。课程管理可以对课程做增删改查,维护分类和标签信息;用户管理可以查看用户列表和用户行为记录。我对接了一下数据库,发现管理后台的操作会实时反映到前台页面,而且管理员给课程打的标签会直接影响基于内容的推荐效果。所以管理后台不只是凑功能用的,它是整个推荐系统数据维护的入口。
前台门户包含课程首页、课程详情、学习中心和推荐专区。课程首页是整个系统的门面,推荐列表就在首页的核心位置,调用的是推荐接口;课程详情页会显示课程的标签和相关信息;学习中心记录用户的学习轨迹。整个前台页面走的是经典的Bootstrap+Thymeleaf模板方案,没有用前后端分离架构,这对于传统SSH/SSM框架学习者更友好。
6. 部署运行与问题排查实录
6.1 从零起步部署指南
这套系统的运行环境要求:JDK 1.8及以上、Maven 3.6+、MySQL 5.7+、Hadoop 2.7+(伪分布式即可)。我建议准备一个Linux虚拟机,或者直接用Windows系统装好这些环境也行。部署过程分四步走,我踩过坑的地方会特别标注。
第一步,初始化数据库。源码的sql目录下有两个脚本,一个建库建表,一个插入初始课程数据。这个步骤容易踩的坑是MySQL版本兼容性问题,如果你用的是MySQL 8.0,需要改一下数据库驱动和连接URL里的时区参数,否则会报连接超时。
# MySQL 8.0 需要调整的配置 spring.datasource.url=jdbc:mysql://localhost:3306/edu_recommend?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver第二步,配置Hadoop环境。进到bigdata模块,修改core-site.xml和hdfs-site.xml里的路径配置。我推荐直接把Hadoop装成伪分布式模式,也就是一台机器同时模拟NameNode、DataNode和JobTracker的集群角色。对于这个项目的体量,伪分布式足够展示大数据处理流程了。装好之后记得先把HDFS格式化并启动服务,然后用脚本把行为日志数据上传到HDFS指定目录。
第三步,启动推荐离线计算任务。打开bigdata模块的MapReduce任务入口类,输入参数指定输入路径和输出路径:hadoop jar edu-recommend.jar /input/logs /output/recommend。任务跑完之后去输出目录查看结果文件,确认推荐结果已经生成。注意在这一步经常遇到的问题:本机没有配置免密钥登录,导致Hadoop无法启动或任务卡在资源等待状态。
第四步,启动Web服务。在项目根目录执行mvn spring-boot:run,或者先mvn clean package再java -jar运行打出来的jar包。等待Tomcat端口启动成功后,浏览器访问http://localhost:8080就是前台首页,访问http://localhost:8080/admin是后台管理页面。
6.2 运行效果实测记录
我在本地完整跑通了整个流程。用测试账号登录后,第一次访问首页能看到推荐专区里展示的课程,这些是基于注册时选择的兴趣标签计算出来的初始推荐。接着我浏览了几门大数据方向的课程,把其中一门加入了收藏,又打开了一个Spark课程的视频页面在里面停留了几分钟。
第二天我再次登录,发现推荐列表发生了明显变化:之前浏览过的Spark和Flink课程出现在靠前的位置,大数据分类下的其他课程也能看到了,还有一门我之前没浏览过的机器学习入门也出现在推荐中。这说明行为数据确实被采集、处理并反馈到了推荐结果里,整个数据闭环是通的。
在管理后台修改了一门课程的标签之后,刷新前台页面的推荐列表,发现该课程在其他用户的推荐列表中的排名也发生了变化。这也验证了基于内容推荐中课程画像的变化会直接影响推荐结果。
6.3 部署过程中的典型问题速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| Hadoop启动后无DataNode | 格式化后NameNode和DataNode版本不一致 | 删除data目录重新格式化,保持集群版本统一 |
| MapReduce任务卡住不动 | YARN资源不够或未启动NodeManager | 检查内存配置、确认所有Hadoop进程已启动 |
| 数据库连接拒绝 | MySQL端口未开放或密码不对 | 检查连接配置、确认MySQL服务状态、核对账号密码 |
| 推荐列表为空 | 行为数据尚未跑批处理或课程表无数据 | 先手动跑一遍MapReduce任务、确认课程表有数据 |
| 前端页面样式错乱 | 静态资源路径被拦截 | 检查Spring Boot对静态资源的放行配置 |
| 注册用户登录后推荐为空白 | 新用户无历史行为,协同过滤无结果 | 确认基于内容推荐的代码正确启用,注册时填写兴趣标签 |
排查问题的大逻辑记住一条:从数据流转的角度一步步倒推。推荐列表空,先看课程表有没有数据;课程表有数据但推荐还是空,看推荐结果表有没有生成记录;推荐结果表也有,但页面没有展示,那就是接口调用或者前端渲染的问题。不要一上来就怀疑算法代码写错了。
6.4 部署时的环境与资源避坑建议
根据我跑这套系统的实际体验,给几条硬核避坑建议。第一,Hadoop环境变量务必配置好,JAVA_HOME、HADOOP_HOME都要指到准确位置,很多人跑不起来就是环境变量引起的。第二,伪分布式模式的NameNode端口默认是9870(Hadoop 2.x是50070),访问Web UI确认集群健康状态,不要拿着旧教程里的端口去访问。第三,服务器内存别低于4G,Hadoop本身要占不少内存,再加上MySQL和Spring Boot,内存太小会频繁GC。第四,代码里如果出现过时API不影响运行就别动它,比如有些集合工具类的方法在新版JDK里标记了过时但还能用,这时候使用新API反而可能引入兼容性问题。
7. 二次开发与效果评估扩展
7.1 推荐效果评估指标体系
跑通了不代表做得好,你得有一套评估推荐效果的指标。源码里没有现成的评估模块,我可以告诉你常用的三个指标,你自己量力加。准确率和召回率看的是推荐列表中有多少是用户真正感兴趣的;覆盖率看的是推荐系统是否只推少数热门课程,是否给长尾课程曝光机会。实操的时候可以在日志表里记录每次推荐的曝光和用户点击,然后统计点击率(CTR = 点击次数/曝光次数),这是最直观的推荐效果指标。
另外把数据随机分成训练集和测试集,用训练集算推荐列表,在测试集上算准确率和召回率,是学术界标准的离线评估方式。如果你想把评估代码加进去,注意一个细节:时间切分。不能随机划分,要按时间切分,用前80%时间的数据预测后20%时间的数据,否则用未来的数据预测过去的行为,指标虚高但没有任何意义。
7.2 可以做的功能增强方向
如果你不满足于现在这个版本,我给你指几个可落地的改进方向。方向一是增加实时行为反馈,用Redis存用户最近一小时的浏览记录,在用户刷新推荐列表时实时调整排序权重,让推荐结果更“跟手”。方向二是引入基于深度学习的推荐模型,比如DeepFM或者Wide&Deep,把用户和课程的特征向量放进神经网络训练,这种模型能捕捉更多特征交互关系,在召回率上通常会优于传统协同过滤。方向三是增加推荐解释模块,告诉用户“因为你学过Spark,所以推荐Flink”,这种可解释性能提高用户对系统的信任度。
我个人建议先做方向三,因为它的实现成本最低、效果却最直观。在推荐结果表里增加一个推荐理由字段,展示推荐算法判断的依据来源,前端展示出来即可。这个功能不用动算法,只要把日志里记录的相似用户或相似课程关联起来就能生成。做完之后,整个系统的演示效果会提升一个档次。
7.3 源码学习的方法与路径建议
最后说点关于源码学习本身的体会。拿到一套源码不要先急着跑,也不要逐行从头读到尾,我的习惯是“按链路读”:先找到入口Controller -> 服务层 -> 算法层 -> 数据层的调用链路,从一次完整请求理解整个系统的运行机制,然后才去看关键接口的具体实现。读源码过程中要做笔记,记录核心方法的输入输出和调用关系,不然看后面忘前面。
对于这套系统,我建议的学习路径是:第一遍搭环境跑通,目标是让系统在本地正常展示推荐结果——这一步建立信心;第二遍读推荐模块的代码,把协同过滤和基于内容推荐的实现逻辑逐行走通——这一步收获算法落地能力;第三遍读大数据处理模块,理解日志数据如何被清洗和计算——这一步理解数据工程。三遍下来,你对该项目的理解深度会完全不一样。
8. 写在最后的一些经验之谈
整个项目我从下载源码到彻底跑通,再到把代码逻辑理清楚,前后花了两天时间。中间碰到过Hadoop启动失败、推荐结果为空、数据库连接不上等一堆问题,基本都是靠上面提到的方式解决的。这套源码本身完成度不错,适合动手能力强的人去跑,更适合作为基础去改造成自己的项目——建议你替换掉课程数据,加上自己想加的功能,把代码风格统一一下,这样交出去的东西才会真正成为你自己的能力证明。
最后再分享一个小技巧:在给别人展示这个项目时,提前准备好几组不同的测试账号,一组是新注册用户、一组是有大量学习行为的用户、一组是兴趣标签差异很大的用户,现场分别登录展示推荐结果的差异,这个演示效果比任何口头解释都更有说服力。