ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

电商个性化推荐系统实战:大数据毕设带你跑通离线与实时链路

电商个性化推荐系统实战:大数据毕设带你跑通离线与实时链路 简介这份基于大数据的电商个性化推荐系统毕业设计论文适合计算机、电子商务、大数据相关专业学生用于毕设选题和设计参考也可帮助推荐系统初学者理解从数据预处理到推荐落地的完整链路。其核心价值在于针对电商平台商品信息过载、用户难以高效选购导致流失的问题设计并实现了一套融合离线与实时能力的智能推荐方案。资源包为单个PDF文件大小约3MB内容紧凑但覆盖系统分析、体系架构设计、系统实现与测试验证的全过程。论文详细介绍了用户行为分析、兴趣建模、商品相似度计算与实时推荐等需求并采用分层架构将系统划分为离线推荐、实时推荐和业务系统三部分实现部分完整给出MongoDB、Spark、Zookeeper、Kafka等大数据组件的单节点配置、项目框架搭建、数据加载处理、统计服务及商品相似度矩阵的代码级实现思路测试章节则围绕推荐效果与系统稳定性展开验证方法。目前已有470人学习下载适合作为毕业设计论文撰写及推荐系统项目实践的直接参考资料。1. 这门毕业设计不是写论文是让你亲手跑通一套电商推荐系统每年毕业季都能看到一类尴尬场景论文写得头头是道答辩时被问「你系统里 ALS 算法的参数怎么调的」当场卡壳。这份《基于大数据的电商个性化推荐系统毕业设计论文》不一样的地方在于它把「写论文」和「做系统」绑定到了一起——你拿到的不仅是一篇文稿而是一条从 MongoDB 数据存储、Spark 离线计算、Flume Kafka 日志采集、Spark Streaming 实时推荐到前端展示的完整链路。换句话说它是一份「能复现的工程设计说明书」不是挂在知网里的纸面功夫。这套系统解决的核心问题很实在电商平台商品太多用户找不到想要的平台留不住人。它通过离线推荐ALS 协同过滤 商品相似度矩阵和实时推荐基于用户最近评分行为两条腿走路再配合 Redis 缓存和 MongoDB 落库形成一个推荐闭环。适合三类人大数据方向毕设选题还没定的本科生、想快速搭一套推荐系统demo的开发者、以及需要技术兜底来充实论文实验章节的研究生。你不需要从零造轮子源码包、数据集、环境配置命令、论文正文都在里面要做的是一步步把它跑起来然后理解每一层为什么这么设计。2. 离线 实时双层架构先把推荐系统的骨架搭明白2.1 为什么必须拆成离线推荐和实时推荐两条链路推荐系统最怕两件事一是算得太慢用户在点鼠标你在跑全量数据二是算得太粗用户刚看完一双鞋你还在推他上周搜过的手机壳。这套系统给的方案是把计算拆成两个时间尺度。离线推荐跑的是批量任务处理的是 MongoD B里的历史数据——用户历史评分、商品信息、标签数据等。它负责产出两类结果一类是统计型结果比如商品平均评分、评分个数、最近评分个数另一类是算法型结果通过 ALS 矩阵分解算出「用户可能喜欢的商品」和「商品之间的相似度」。这些结果写回 MongoDB前端直接查询展示。特点是大而全但更新频率低按天或按小时跑一次就够了。实时推荐跑的是流式任务链路是 Flume 监控 Tomcat 日志 → 推送 Kafka → Spark Streaming 消费 → 结合 Redis 里存的用户最近评分队列 → 实时算出新的推荐结果 → 合并回 MongoDB。它只盯着用户最近的动作——刚刚给哪个商品打了分、评分是 3 分还是 5 分这些信号直接改变推荐结果。简单说离线推荐负责「猜个大概」实时推荐负责「根据你的最新动作马上修正」。这套双层架构是当前工业界的标准做法。只用离线推荐用户行为响应慢只用实时推荐冷启动时没有历史数据可算。两者互补论文里也有对应的架构图和数据流程图照着讲就能把「为什么这么设计」说清楚。2.2 七个核心组件各干一件事系统涉及的技术组件不少但职责边界非常清晰下面按数据流向逐个说明。组件版本参考职责MongoDB3.4.3主数据库存商品、评分、标签、用户表以及离线和实时推荐结果Redis4.0.2缓存数据库存用户最近评分队列支撑实时推荐的高速读取Spark2.1.1离线统计 ALS 推荐算法 Spark Streaming 实时计算Zookeeper3.4.10Kafka 的协调服务单节点用 standalone 模式Kafka0.10.2.1消息队列承接 Flume 采集的日志并转发给 Spark StreamingFlume1.8.0日志采集监控业务服务运行日志实时推送评分行为Azkaban未指定离线任务调度定时触发统计和推荐任务需要特别注意的是数据模型设计。商品表Product里有个字段叫 tags用的是|分隔的 UGC 标签评分表Rating的字段是 userId、productId、score、timestamp后面实时推荐的数据流UID|MID|SCORE|TIMESTAMP就是从这张表来的。推荐结果不直接覆盖写入而是单独存在 ProductRecs、UserRecs、StreamRecs 三张表里这样离线结果、实时结果可以独立更新、混合展示。2.3 数据流闭环从一条评分日志到前端推荐位当你给商品打了 4 分这条动作流经的路径是这样的业务系统Spring 服务收到评分请求写入 MongoDB 的 Rating 表同时通过日志框架输出一行日志到 Tomcat。Flume 监控到这个日志更新解析出评分行为实时推送到 Kafka 的某个 topic。Kafka Stream 程序消费这个消息过滤出UID|MID|SCORE|TIMESTAMP格式的评分数据流再发送到另一个 Kafka 队列即完成一次消息的清洗和转发。Spark Streaming 监听这个队列拿到新评分后结合 Redis 里缓存的该用户最近评分记录一起提交给实时推荐算法。算法算完把新的推荐列表和 MongoDB 里已有的推荐结果合并更新 StreamRecs 表。前端通过业务服务查询 MongoDB把 UserRecs离线、StreamRecs实时、ProductRecs相似商品混合展示。这个链路里最容易出问题的环节在第 4 步——Redis 里存的是什么不是全部历史评分只存最近一段时间比如最近 20 条的评分记录。这样实时算法只需要在很小的数据集上做计算延迟控制在秒级。论文第四章到第六章的内容全是围绕这条链路展开的。3. 单节点环境搭建五件套装完等于拿到入场券3.1 MongoDB 3.4 安装与配置这是整个系统的数据底座安装步骤没什么玄学但配置文件的几个参数值得留神。# 下载 MongoDB 3.4.3 Linux 版本 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.4.3.tgz # 解压到用户目录 tar -xf mongodb-linux-x86_64-rhel62-3.4.3.tgz -C ~/ # 移动到最终安装目录 mv mongodb-linux-x86_64-rhel62-3.4.3/ /usr/local/mongodb # 创建数据目录和日志目录 mkdir -p /usr/local/mongodb/data/db mkdir -p /usr/local/mongodb/data/logs # 创建配置文件 touch /usr/local/mongodb/data/mongodb.conf配置文件内容如下port 27017 dbpath /usr/local/mongodb/data/db logpath /usr/local/mongodb/data/logs/mongodb.log fork true logappend true # auth true启动和验证# 启动服务 sudo /usr/local/mongodb/bin/mongod -config /usr/local/mongodb/data/mongodb.conf # 连接测试 /usr/local/mongodb/bin/mongo # 停止服务 sudo /usr/local/mongodb/bin/mongod -shutdown -config /usr/local/mongodb/data/mongodb.conf这里有个细节fork true表示后台运行日志会写到 logpath调试时建议把 fork 改成 false 前台运行能看到完整启动日志。auth true被注释掉了单机环境不需要开认证等系统真正上线再考虑权限问题。数据目录dbpath必须手动创建MongoDB 不会自动建目录这是最常见的启动失败原因。3.2 Redis 4.0 安装实时推荐的加速器Redis 在系统里承担的是「用户最近评分队列」的存取要求低延迟、高并发。源码编译安装的步骤比较多但核心就三步解压、编译、改配置。# 下载源码包 wget http://download.redis.io/releases/redis-4.0.2.tar.gz # 解压 tar -xf redis-4.0.2.tar.gz -C ~/ # 进入源码目录安装 gcc 后编译 cd redis-4.0.2/ sudo yum install gcc make MALLOClibc sudo make install # 复制配置文件到 /etc 并修改 sudo cp ~/redis-4.0.2/redis.conf /etc/ sudo vim /etc/redis.conf修改配置项daemonize yes pidfile /var/run/redis/redis.pid logfile /var/log/redis/redis.log dir /usr/local/rdbfilemake MALLOClibc这行值得说一句Redis 默认用的是 jemalloc 内存分配器在某些 Linux 版本上编译会报错显式指定 libc 可以绕过去。另外dir参数指定的是持久化文件存放目录/usr/local/rdbfile需要提前创建否则 Redis 启动没问题但写 RDB 快照时会失败。启动验证redis-server /etc/redis.conf redis-cli redis-cli shutdown3.3 Spark 2.1.1 配置离线和实时计算的引擎Spark 负责的活最重离线统计用 Spark Core Spark SQL离线推荐用 MLlib 的 ALS实时计算用 Spark Streaming。单节点部署只需要改动两个配置文件。# 下载 Spark 2.1.1 wget https://d3kbcqa49mib13.cloudfront.net/spark-2.1.1-bin-hadoop2.7.tgz # 解压到安装目录 tar -xf spark-2.1.1-bin-hadoop2.7.tgz -C ./cluster # 进入安装目录 cd spark-2.1.1-bin-hadoop2.7/ # 配置 slaves 文件 cp ./conf/slaves.template ./conf/slaves vim ./conf/slaves # 内容写上主机名linux # 配置 spark-env.sh cp ./conf/spark-env.sh.template ./conf/spark-env.sh vim ./conf/spark-env.sh # 添加以下两行 SPARK_MASTER_HOSTlinux SPARK_MASTER_PORT7077启动方式# 启动 Spark 集群 sbin/start-all.sh # 浏览器验证 # 访问 http://linux:8080 # 关闭 sbin/stop-all.sh注意SPARK_MASTER_HOST要填你的机器 hostname不要填 localhost否则 worker 注册不上。启动后浏览器打开 8080 端口能看到 worker 列表显示 1 个存活节点才算成功。3.4 Zookeeper 和 Kafka消息链路的地基Kafka 依赖 Zookeeper 做协调所以先装 Zookeeper 再装 Kafka顺序不能反。# 下载 Zookeeper 3.4.10 wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz # 解压 tar -xf zookeeper-3.4.10.tar.gz -C ./cluster cd zookeeper-3.4.10/ # 创建数据目录 mkdir data/ # 复制配置模板 cp ./conf/zoo_sample.cfg ./conf/zoo.cfg # 修改数据目录 vim conf/zoo.cfg dataDir/home/bigdata/cluster/zookeeper-3.4.10/data # 启动和验证 bin/zkServer.sh start bin/zkServer.sh status # 输出 Mode: standalone 表示单机模式正常Zookeeper 启动后接着装 Kafka# 下载 Kafka 0.10.2.1 wget http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/0.10.2.1/kafka_2.11-0.10.2.1.tgz # 解压 tar -xf kafka_2.11-0.10.2.1.tgz -C ./cluster cd kafka_2.11-0.10.2.1/ # 修改 server.properties vim config/server.properties host.namelinux port9092 zookeeper.connectlinux:2181Kafka 的启动和 topic 验证是连在一起的# 启动 Kafka bin/kafka-server-start.sh -daemon ./config/server.properties # 创建 topic bin/kafka-topics.sh --create --zookeeper linux:2181 \ --replication-factor 1 --partitions 1 --topic recommender # 验证生产者消费者 bin/kafka-console-producer.sh --broker-list linux:9092 --topic recommender bin/kafka-console-consumer.sh --bootstrap-server linux:9092 --topic recommenderreplication-factor 1和partitions 1在单机环境下是必须的副本数超过 1 时 Kafka 会因为找不到第二个 broker 而报错。producer 和 consumer 两个终端都起来后在 producer 里随便输入一行字符consumer 能收到就说明整条 Kafka 链路通了。Flume 这里先装好但不急着配它属于项目部署环节和日志格式强绑定。4. 核心算法与数据加载ALS 怎么算出商品相似度4.1 数据加载从 MongoDB 到 Spark RDD数据准备好了接下来要打通 MongoDB 和 Spark 之间的数据通道。常见做法是用MongoSpark库通过配置连接参数直接加载集合数据。// 建立 SparkSession指定 MongoDB 连接 val spark SparkSession.builder() .appName(DataLoader) .master(local[*]) .config(spark.mongodb.input.uri, mongodb://linux:27017/recommender.ratings) .config(spark.mongodb.output.uri, mongodb://linux:27017/recommender.recs) .getOrCreate() // 加载评分数据 val ratingDF MongoSpark.load(spark, ReadConfig(Map(collection - ratings), ReadConfig(spark.sparkContext.getConf)))逻辑说明这里的关键是把 MongoDB 集合映射成 DataFrame。input.uri对应读路径output.uri对应写路径加载的 ratingDF 包含 userId、productId、score、timestamp 四列。参数说明local[*]表示本地多线程运行毕设阶段数据量不大不需要提交到集群若数据量大需要把.master(local[*])去掉改用spark-submit提交。4.2 统计服务框架平均评分和热度榜离线统计做三件事商品平均评分、商品评分个数、最近商品评分个数。前两个是全量统计第三个按时间维度筛选。-- 商品平均评分 INSERT INTO AverageProductsScore(productId, avg) SELECT productId, AVG(score) FROM ratings GROUP BY productId; -- 商品评分个数 INSERT INTO RateMoreProducts(productId, count) SELECT productId, COUNT(*) FROM ratings GROUP BY productId; -- 最近商品评分个数按年月筛选 INSERT INTO RateMoreProductsRecently(productId, count, yearmonth) SELECT productId, COUNT(*), SUBSTRING(timestamp, 1, 6) AS yearmonth FROM ratings WHERE timestamp 2023-01 GROUP BY productId, yearmonth;逻辑说明这三张统计表是离线推荐的「基础热度信号」虽然没有直接用于 ALS 训练但它们在混合推荐里起到兜底作用——冷门商品没有足够的评分数据时用热度推荐顶上。实现时用 Spark SQL 的 DataFrame API 等价写法性能差异不大。参数说明SUBSTRING(timestamp, 1, 6)会把2023-01-15截成2023-01这就是 RateMoreProductsRecently 表里yyyymm字段的来历。4.3 ALS 矩阵分解用户推荐矩阵的生成ALS交替最小二乘法是这套系统的核心算法输入是评分矩阵输出是用户因子矩阵和商品因子矩阵两个矩阵相乘就得到预测评分矩阵。import org.apache.spark.ml.recommendation.ALS // 准备训练数据只需要三列 val trainDF ratingDF.select(userId, productId, score) // 创建 ALS 模型 val als new ALS() .setMaxIter(10) // 最大迭代次数 .setRank(10) // 隐因子个数 .setRegParam(0.1) // 正则化参数 .setUserCol(userId) .setItemCol(productId) .setRatingCol(score) // 训练模型 val model als.fit(trainDF) // 为每个用户生成 top 20 推荐 val userRecs model.recommendForAllUsers(20)逻辑说明ALS 的原理是把评分矩阵分解成两个低维矩阵rank就是低维空间的维度。setMaxIter(10)控制迭代次数不是越大越好——数据集小的时候迭代 20 次和 10 次结果几乎一样但耗时翻倍。setRegParam(0.1)是过拟合开关数据稀疏时适当调大数据稠密时调小。参数说明recommendForAllUsers(20)返回的是每个用户得分最高的 20 个商品格式为(userId, Array[(productId, score)])这个输出直接写入 MongoDB 的 UserRecs 表。4.4 商品相似度矩阵从用户行为反推商品关联商品相似度矩阵的算法思路是利用 ALS 训练出的商品因子矩阵两两计算余弦相似度。因为商品因子向量已经压缩到低维空间计算量可控。import org.apache.spark.ml.linalg.Vectors import org.apache.spark.sql.functions._ // 从模型中提取商品因子 val productFactors model.itemFactors .select(id, features) // 将 features 转为向量并缓存 val productVector productFactors.map { row val id row.getInt(0) val features row.getSeq[Float](1).map(_.toDouble).toArray (id, Vectors.dense(features)) }.toDF(productId, vector).cache() // 笛卡尔积计算余弦相似度取每行 top 10 val simDF productVector.as(a) .join(productVector.as(b), col(a.productId) ! col(b.productId)) .select( col(a.productId).as(productId), col(b.productId).as(simProductId), cosineSimilarity(col(a.vector), col(b.vector)).as(score) )逻辑说明这个计算有个明显的性能坑——商品数量是 N 时笛卡尔积会产生 N² 条数据。一万个商品就是一亿条单机跑会直接内存溢出。常见做法是先按类别过滤只计算同类别商品之间的相似度或者用approxSimilarityJoinLSH 局部敏感哈希代替精确计算。毕设阶段数据量小直接全量算没问题但代码注释里要写上这个优化空间答辩时能加分。参数说明结果按 score 降序排序后每组 productId 取前 10 个相似商品写入 ProductRecs 表。4.5 实时推荐数据流一个评分动作如何改变推荐位实时部分的核心逻辑在 Spark Streaming 程序里它消费 Kafka 中过滤后的评分数据流结合 Redis 的最近评分队列算出新的推荐结果。import org.apache.kafka.common.serialization.StringDeserializer import org.apache.spark.streaming.kafka010._ val kafkaParams Map[String, Object]( bootstrap.servers - linux:9092, key.deserializer - classOf[StringDeserializer], value.deserializer - classOf[StringDeserializer], group.id - recommender-stream, auto.offset.reset - latest, enable.auto.commit - (false: java.lang.Boolean) ) // 输入格式UID|MID|SCORE|TIMESTAMP val messages KafkaUtils.createDirectStream[String, String]( streamingContext, LocationStrategies.PreferConsistent, ConsumerStrategies.Subscribe[String, String](List(recommender), kafkaParams) ) // 解析评分数据 val ratingStream messages.map(_.value()) .map { line val arr line.split(\\|) (arr(0).toInt, arr(1).toInt, arr(2).toDouble, arr(3).toLong) }逻辑说明createDirectStream是 Kafka 0.10 之后推荐的消费方式直接从 broker 拉数据不再依赖 Zookeeper 维护 offset避免 consume 延迟导致的重复消费。enable.auto.commit设为 false意味着 offset 由程序控制保证处理完再提交。参数说明auto.offset.reset设为latest表示只消费新数据调试时如果发现实时推荐没反应改成earliest能追历史数据排查问题。实时推荐算法本身不复杂拿到用户新的评分后从 ProductRecs 表里找出与该商品最相似的 10 个商品过滤掉用户已经评分过的按相似度分数排序输出。结果写入 StreamRecs 表前台查询时把 UserRecs 和 StreamRecs 的结果合在一起。5. 避坑指南单机跑这套系统容易翻车的五个地方5.1 内存不足Spark 任务跑到一半 Executor 丢失现象提交 ALS 训练任务后日志显示 Executor Lost或者 JVM 直接 OOM任务反复重试最终失败。原因单机部署时 Spark 默认会用掉所有可用内存而 Zookeeper、Kafka、MongoDB 同时也在抢内存。默认配置下 Spark 的 executor 内存上限是机器内存的 1/4但多组件并存时根本不够分。解决在spark-env.sh里显式限制 Spark 内存配额。export SPARK_WORKER_MEMORY2g export SPARK_DRIVER_MEMORY2g如果机器只有 4G 内存建议把 MongoDB 的fork关掉改用前台运行或者直接在配置里限制 MongoDB 的 cache 大小。从那以后我每配一台新机器先看free -h再动手从不相信默认参数。5.2 Kafka 启动失败报错信息指向 broker 注册超时现象执行kafka-server-start.sh后日志出现Timeout while registering broker或者Address already in use。原因第一类是 Zookeeper 没起来就启动 Kafka第二类是host.name配置填了 localhost和实际监听地址不一致。解决确认启动顺序先zkServer.sh start再启动 Kafka配置文件里host.name必须填机器实际 hostname同时/etc/hosts里要有对应的映射。验证方法# 检查 Zookeeper 是否存活 echo ruok | nc linux 2181 # 检查 Kafka 端口 netstat -tlnp | grep 9092如果 netstat 输出为空说明 Kafka 进程已经崩了去logs/server.log看具体异常。常见错误是listeners配置没改0.10.2.1 版本默认监听 localhost必须手动指定。5.3 实时推荐一直不更新Flume 日志里没有评分记录现象给商品打了分MongoDB 的 Rating 表有数据但 StreamRecs 表始终不更新Kafka consumer 收不到消息。原因Flume 监控的日志路径配置错误或者业务系统输出的日志格式不是UID|MID|SCORE|TIMESTAMP。解决分三步排查。# 第一步手动往日志文件里写一条评分记录 echo 1|2|5.0|1672531200000 /usr/local/tomcat/logs/access.log # 第二步观察 Flume 日志 tail -f /usr/local/flume/logs/flume.log # 第三步启动 Kafka consumer 确认消息到达 bin/kafka-console-consumer.sh --bootstrap-server linux:9092 --topic recommenderFlume 配置里spooldir和taildir的差异要搞清楚前者监控整个目录的文件新增后者监控指定文件的追加内容。实时日志采集必须用taildir用spooldir的话每条记录会被重复读取。这是 Flume 1.8 引入 taildir source 的原因之前的版本只能用exectail -F命令绕过。5.4 商品相似度结果全是空笛卡尔积算到一半就炸了现象ProductRecs 表能生成但里面只有几十条记录明显不是全量商品的结果。原因商品数量较大时全量笛卡尔积 N² 条记录超出了 executor 的可用内存部分任务失败被 Spark 静默跳过。注意 Spark 不会直接报错而是把失败任务标记为 skipped继续执行后续任务导致结果不完整。解决两个方案。一是加内存 调大 partitions二是提前过滤掉低热度商品只计算评分次数超过阈值的商品子集。// 过滤评分次数少于 10 的商品 val validProductIds ratingDF.groupBy(productId) .count() .filter(count 10) .select(productId) val filteredVectors productVector.join(validProductIds, productId)这样既减少了计算量还顺带解决了冷启动问题——评分次数太少的商品本身就不适合参与相似度推荐。答辩时讲清楚这个取舍比堆技术名词更能拿分。5.5 前端展示不出推荐结果MongoDB 字段类型对不上现象后台接口能调通MongoDB 里有数据但前端页面空白F12 报 JSON 解析异常。原因ALS 计算结果的Array[(productId, score)]在 MongoDB 里存成了嵌套文档数组但 Java 后端实体类用的是ListRating结构Gson 反序列化时字段名大小写不匹配。解决在写入 MongoDB 前用 DataFrame 的toJSON或手动映射统一字段命名风格。// 写库前指定字段名 userRecsDF.select( col(userId), col(recs).cast(arraystructproductId:int,score:double) ).write.mode(overwrite) .format(mongo) .option(collection, UserRecs) .save()Java 实体类记得加Field(productId)注解或者保持 Java 字段名和 MongoDB 字段名完全一致。这类问题最折磨人因为前后端都能通错位只在序列化层。6. 验证方法与进阶从跑通到能答辩还要做这几件事6.1 离线任务自动化用 Azkaban 调度替代手动执行项目里提到 Azkaban 做离线调度但它没有给出具体的配置步骤。毕设阶段建议至少做到「一键触发」不要每次手动 spark-submit。最简单的做法是写一个 Shell 脚本把三个离线任务串起来#!/bin/bash # 离线推荐任务调度脚本 SPARK_HOME/usr/local/spark-2.1.1-bin-hadoop2.7 # 1. 数据加载 $SPARK_HOME/bin/spark-submit \ --class com.recommender.DataLoader \ --master spark://linux:7077 \ /home/bigdata/recommender-1.0.jar # 2. 离线统计 $SPARK_HOME/bin/spark-submit \ --class com.recommender.Statistics \ --master spark://linux:7077 \ /home/bigdata/recommender-1.0.jar # 3. 离线推荐ALS 相似度 $SPARK_HOME/bin/spark-submit \ --class com.recommender.OfflineRecommender \ --master spark://linux:7077 \ /home/bigdata/recommender-1.0.jar脚本跑通后再让脚本本身进入 Azkaban 的定时调度这就和论文里第四章描述的架构完全对齐了。注意 spark-submit 的--master参数要和 Spark 集群模式一致如果 env 里没配SPARK_MASTER_HOST传给spark://linux:7077会连不上。6.2 推荐效果评估不只是讲 AUC还要讲业务指标答辩时最怕被问「你这个推荐系统效果怎么样」。ALS 的离线评估标准做法是 RMSE但 RMSE 只反映预测评分准不准不反映推荐列表的实际质量。更合适的指标是 PrecisionK 和 RecallK——把用户的实际评分行为当作 ground truth看推荐的 10 个商品里有多少是用户真的评分过的。# Python 评估脚本计算 PrecisionK def precision_at_k(actual, predicted, k10): actual: 用户真实评分的商品集合; predicted: 推荐列表 if not predicted: return 0.0 hit len(set(actual) set(predicted[:k])) return hit / min(k, len(predicted)) # 遍历所有用户的推荐列表取均值 total_precision 0.0 for user_id, recs in user_recs.items(): actual user_rated_products[user_id] total_precision precision_at_k(actual, recs, k10) print(Precision10:, total_precision / len(user_recs))除了算法指标答辩时可以加一个业务维度的描述推荐的 10 个商品里排在前 3 的商品的点击率是否明显高于后 7 个这个数据可以从 Flume 采集的日志里分析出来。不需要做 AB 测试单看点击分布也能说明「推荐排序有效」。6.3 论文写作笔法把系统实现变成论文第二章到第五章这套论文文档的正文结构是现成的第一章写背景和意义信息过载 用户流失第二章系统分析功能描述 业务流程 可行性第三章架构设计分层架构 数据流程 数据模型第四章系统实现环境配置 框架搭建 算法实现第五章系统测试。你自己跑通系统后把截图和日志输出补进去技术描述部分可以改成第一人称。测试部分有个写论文的小技巧不光写「系统正常运行」还要写「压力测试下的表现」。比如测试场景并发用户数平均响应时间结果首页推荐位加载50300ms通过实时推荐更新20800ms通过离线任务调度112min通过这张表的价值在于把「系统能跑」变成「系统在多大量级下还能用」这正是答辩老师想听到的边界信息。从那以后我每次写完系统都会跑一组简单的并发测试哪怕不写进论文自己心里也有底。最后提醒一句把论文、源码、数据集、环境配置命令打包存好答辩之后这套东西还能用在求职作品集里比空口讲「我学过大数据」有说服力得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表