大数据酒店推荐系统毕设实战:从爬虫采集到Spark ALS全流程

发布时间:2026/10/19 12:06:52
大数据酒店推荐系统毕设实战:从爬虫采集到Spark ALS全流程 打开各类毕设交易平台搜大数据关键词你会看到十个里面至少七个是电商数据分析、电影推荐、商品推荐。酒店推荐系统这个题目相对没那么大众但它恰好把大数据方向最常被考察的几个技术模块全串起来了网络爬虫采集、分布式存储、离线批处理、数据仓库建模、协同过滤推荐、数据可视化。这篇文章是我完整做完一个酒店推荐系统毕业设计之后整理出来的不按教程的套路讲而是说说我当时做技术选型、定架构、写代码、调参数、写论文、准备答辩时踩过的坑和总结出来的经验。适合手里正好攥着类似题目、材料还没怎么准备、又想做出点真东西的同学。1. 选题逻辑酒店推荐为什么比电影、电商推荐更适合当毕设1.1 先想清楚毕业设计到底考察什么很多同学一上来就纠结推荐算法要不要用深度学习模型准确率做到多少分才算优秀结果项目做到一半发现根本不是那么回事。毕业设计本质上考察三件事技术链路是否完整、工作量是否可量化、逻辑是否自圆其说。老师不会指望一个本科生或硕士生做出能上线的工业级系统但一定希望看到你具备从数据采集到数据存储、从计算加工到业务展示的全链路能力。电影推荐和电商推荐为什么容易踩坑因为这两类数据太容易拿了公开数据集一抓一大把导致大家做出来的东西高度雷同。你用MovieLens隔壁也用MovieLens答辩PPT翻开来第一页数据集介绍都差不多。酒店推荐的数据维度其实更丰富——价格、位置、星级、设施、评论内容、城市分布这些字段既能支撑协同过滤又能做多维分析还能让可视化大屏做得好看。更重要的是酒店数据的业务直觉很强谁都能理解找酒店看评分、看位置、看价格推荐结果好不好老师看一眼就能判断。1.2 技术栈选型的底层逻辑这个题目用了 Hadoop Spark Hive 三件套。为什么不选 Flink为什么不用一套 Python 直接搞定我当时考虑的核心因素是课程大纲里讲了什么就用什么。Hadoop 的 HDFS 负责存储原始数据Hive 负责把数据整理成结构化数仓Spark 负责跑推荐算法三者各有不可替代的位置。这个组合既不会出现杀鸡用牛刀的质疑也能在论文中把每个组件的角色写得清清楚楚。有同学问过爬虫用 Python推荐也用 Python那是不是可以不引入 Hadoop理论上可以但你想想答辩时老师的问题就来了Python 也能处理数据为什么还需要分布式系统你的回答会非常苍白。引入 Hadoop 和 Hive 的意义不在于制造复杂度而在于让数据流动路径清晰可见——从 HDFS 原始文件到数仓分层表再到特征宽表最后被 Spark 读取训练模型。每一步都有明确的输入输出论文里每一章都有内容可写。1.3 一个容易被忽视的选题风险酒店推荐系统不是完全没有坑。最大的风险是数据量不够导致推荐效果像随机猜测。如果只爬几百条酒店数据用户评分矩阵会极度稀疏ALS 算法的 RMSE 会很难看答辩演示时推荐出来的酒店和用户画像完全对不上场面就尴尬了。这个问题我在后面单独开一节详细说这里先给结论爬虫阶段必须控制好数据规模下限我当时是锁定了5个城市的公开信息采集了大约8000条有效数据评分数据通过模拟行为扩充到6万多条才能把模型指标稳定在一个能解释的水平。2. 系统架构四个模块的分工与数据流转方向2.1 一条完整的数据链路整个系统的核心流程并不复杂画出来就一条主线采集层Scrapy - 原始数据落盘为CSV/JSON - 上传到HDFS - Hive外部表ODS层 - 数据清洗与数仓分层DWD/DWS - 特征宽表 模拟用户行为评分表 - Spark读取数据训练ALS推荐模型 - 推荐结果写回MySQL - 后端API查询MySQL - 前端ECharts可视化展示这条链路里最容易被忽略的是推荐结果要写回MySQL这一步。很多同学把模型结果直接存在 HDFS 里然后前端又不知道该怎么读 HDFS最后只能把推荐结果手动截图放进论文里。正确做法是Spark 训练完模型后对每个用户生成 TopN 推荐列表用 JDBC 写进 MySQL 的业务表后端 Web 服务只需要查 MySQL 就能拿到推荐数据。HDFS 面向批处理MySQL 面向在线查询各司其职这才是合理的工程分工。2.2 每个模块的技术选型与产出物我把模块划分、技术方案和产出物整理成了一张表做论文架构设计的时候可以直接参考模块核心任务主要技术产出物数据采集从公开网站采集酒店基础信息Scrapy Selenium 混合方案酒店信息CSV、城市维表数据存储与仓库原始数据入HDFS完成清洗与建模Hadoop HDFS HiveODS/DWD/DWS三层表推荐引擎训练离线推荐模型并输出TopN结果Spark MLlib ALS推荐结果表、模型评估指标可视化系统展示酒店数据分析和推荐效果Vue ECharts Flask可视化大屏、推荐接口架构设计上有个关键原则模块之间只通过数据文件或数据库表通信不互相依赖代码接口。爬虫只管产CSVHive只管查HDFS上的表Spark只管读Hive表写MySQL谁都不需要了解对方内部实现。这样每个模块都能独立开发、独立测试最后联调时只要确认数据格式对得上就行。我当时是并行开发的爬虫写到一个阶段就开始设计数仓表结构火花那边等特征表稳定再动整体进度压缩了至少两周。2.3 前后端技术要不要上SpringBoot很多同学的毕设技术栈里有要求必须用 Spring Boot 写后端。如果你的项目没有强制规定我建议后端用 Flask 而不是 Spring Boot。原因很简单这个项目的后端只需要提供三四个读取MySQL的接口Spring Boot 启动慢、配置多、依赖重对毕业设计的时间成本不友好。但如果学校明确规定必须用 Java 技术栈那就用 Spring Boot 写个轻量 REST API也是很成熟的做法。一个前端展示的小经验可视化大屏如果用 Vue ECharts公共组件和页面本身要拆开地图、柱状图、饼图、推荐卡片四个组件可以并行写最后拼在 dashboard 页面里。接口数据格式要和组件设计同步定下来避免前后端各写各的联调时改格式改到崩溃。3. 爬虫部分数据量、字段设计与异常处理实战3.1 数据源选择与合规边界酒店数据从哪来最稳妥的方案是选择公开网页上公开展示的信息比如公开网站的可浏览页面。采集前需要看目标网站的 robots 协议设置合理抓取间隔不要用分布式爬虫去压别人的服务器。毕设阶段不建议碰需要登录才能看到的数据也不建议用任何破解手段万一触发法律风险得不偿失。我认为爬虫部分真正拉开差距的地方在两点一是爬取策略的完整性二是数据质量的保障。策略上我用了 Scrapy 作为主框架因为 Scrapy 自带请求调度、去重过滤、中间件机制处理几百个酒店页面的翻页列表非常合适。列表页只拿到酒店名称和ID详情页还要单独请求一次才能拿到评分、价格、评论数这些明细字段所以爬虫要分两级列表页解析出 URL交给调度器再抓详情页。3.2 字段设计决定后续所有工作字段怎么设计直接决定了数仓建模和推荐特征的可用性。我当时定义的酒店基础信息字段如下{ hotel_id: 数字ID全局唯一, hotel_name: 酒店名称, city: 所在城市, district: 行政区/商圈, star_level: 星级整数类型, avg_price: 日均价浮点型将¥458起转为458, score: 用户评分浮点型0到5, comment_count: 评论数整数, lat: 纬度浮点, lng: 经度浮点, facilities: 设施列表用英文分号拼接, tags: 标签如近地铁亲子等用竖线分隔 }价格字段是个典型的坑。网页上展示的是¥458起如果你直接存字符串后面Hive里做价格区间统计就得写一连串正则替换。正确做法是在爬虫的 Item Pipeline 里就把字符串清洗成标准格式去掉货币符号、起字遇到暂无报价标记为0或NULL最后统一成 float 类型。数据从源头就洗干净后面数仓层的压力会小非常多。3.3 反爬处理与断点续爬我用的反爬策略比较常规随机 User-Agent、请求间隔控制在2到5秒、同一个 IP 不对同一个域名短时间高频访问。遇到验证码页面时我的方案是把它记录下来等晚上手动处理后再从断点续爬。Scrapy 提供了JOBDIR参数支持暂停和恢复当时我靠这个功能解决了爬了三个小时突然被封IP导致全量重爬的问题。中文编码的坑也必须提。Scrapy 导出 CSV 默认可能用 utf-8在 Windows 上打开会乱码。我在 settings 里设置FEED_EXPORT_ENCODING utf-8-sig同时用FEED_EXPORT_FIELDS固定了字段顺序。这个细节看着小但直接影响你后面读数据时的体验早设置早省心。4. Hive数仓建模从原始文件到推荐特征表4.1 ODS层HDFS外部表的创建方式爬虫产出的 CSV 上传到 HDFS 后需要通过 Hive 建表来读取。我强烈建议建外部表不要用内部表。原因是数据文件可能还要重新生成外部表删掉表结构不会连带删掉 HDFS 上的文件容错性更好。建表白语句的关键在于 SerDe 配置和分隔符匹配。CSV 文件我统一用逗号分隔但如果某个字段内部也含逗号比如设施列表解析就会错位。我当时把分隔符换成了\001Hive 默认 SerDe 使用的控制字符爬虫导出时用gzip压缩效果很好。CREATE EXTERNAL TABLE IF NOT EXISTS ods_hotel_info ( hotel_id STRING, hotel_name STRING, city STRING, district STRING, star_level INT, avg_price DOUBLE, score DOUBLE, comment_count INT, lat DOUBLE, lng DOUBLE, facilities STRING, tags STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY \001 STORED AS TEXTFILE LOCATION /data/hotel/ods/hotel_info;4.2 数仓为什么要分层毕设也要说清楚很多人觉得毕设就几万条数据不搞分层也能跑通。但你换位思考一下如果你的论文里只出现了一张表从爬虫数据到推荐结果全靠一条 SQL 搞定那Hive数仓这门技术在你项目里的存在感就非常弱。看起来只是用Hive查了下数本质没有体现数仓设计能力。分层的意义在于让每一层有明确职责ODS层原样存储不加工保留初始数据状态DWD层清洗后明细数据字段标准化维度退化处理DWS层按业务主题汇总比如酒店主题的评分、价格、热度统计DWD层的清洗SQL有几个典型操作值得写进论文。去重用row_number() over(partition by hotel_id order by comment_count desc)取rn1保证同一个酒店只保留一条有效记录空值处理用coalesce(avg_price, 0)价格区间字段用case when做分桶比如经济型0-300、舒适型300-600、豪华型600以上。这种清洗工作不复杂但足够体现你对数据质量的把控能力。4.3 用户行为数据毕设里绕不开的仿真问题到这一步会面临一个所有推荐系统毕设都会遇到的灵魂拷问用户评分数据从哪来真正的平台用户行为是拿不到的所以只能构造模拟行为数据。这不是什么不可告人的事情关键在于逻辑要合理论文里明确说明这是模拟数据并且用同样逻辑随机出训练集和测试集来评估模型效果。我当时是这样设计的定义50个模拟用户每个用户配置一个偏好向量偏好类型包括商务出行、亲子出游、情侣度假、性价比、位置优先五类。然后按照酒店的城市、星级、价格、标签与用户偏好的匹配程度打分完全匹配5分部分匹配3到4分不匹配1到2分再按5%的概率随机增减1分模拟噪声这个逻辑写成一个 Python 脚本输入酒店特征表输出用户ID、酒店ID、评分三列生成大约6万条评分记录。数据量不大但足够让 ALS 算法跑出收敛的损失曲线。论文中如实写用户行为数据由规则模拟生成用于验证推荐系统技术链路的可行性是学术上可以接受的做法。5. Spark推荐引擎ALS模型训练与参数调整实录5.1 ALS协同过滤的原理一句话说透推荐算法很多为什么选 ALS因为 ALS交替最小二乘是协同过滤家族里最成熟、Spark MLlib 里封装最好、调参路径最清晰的算法。它的核心思想是把用户-酒店评分矩阵分解成两个低维矩阵——用户隐特征矩阵和酒店隐特征矩阵两个矩阵相乘后重新逼近原始评分矩阵。矩阵分解的过程通过交替固定一方、优化另一方来迭代求解所以叫交替最小二乘。用大白话解释系统不知道你为什么不打高分但只要你打过分它就从高分酒店里提取共性特征价格区间、区域、星级等再从低分酒店里提取反面特征多轮迭代后就能预测你没打过分的那家酒店会得几分。ALS的隐性优势是不需要任何用户画像或文本特征只需要评分矩阵这正适合我前面构造的模拟评分数据。5.2 训练与评估代码核心片段使用 PySpark 训练模型代码结构非常直接。当时我用的是 Spark 2.4 版本代码兼容性较好from pyspark.sql import SparkSession from pyspark.ml.recommendation import ALS from pyspark.ml.evaluation import RegressionEvaluator spark SparkSession.builder \ .appName(HotelRecommendALS) \ .master(local[*]) \ .config(spark.driver.memory, 2g) \ .getOrCreate() ratings_df spark.read.table(dws_user_hotel_rating) train_df, test_df ratings_df.randomSplit([0.8, 0.2], seed42) als ALS( userColuser_id, itemColhotel_id, ratingColrating, coldStartStrategydrop, rank20, regParam0.05, maxIter15 ) model als.fit(train_df) predictions model.transform(test_df) evaluator RegressionEvaluator( metricNamermse, labelColrating, predictionColprediction ) rmse evaluator.evaluate(predictions) print(fRMSE {rmse:.4f})代码里有几个细节值得注意。coldStartStrategydrop会让测试集中从未出现过的用户和酒店在预测时被丢弃避免产生NaN预测值randomSplit的种子固定为42保证可复现性写论文时能给出稳定的指标。5.3 调参过程中的实际数据表现我调参用的是最简单粗暴的方式——网格搜索rank 取值 [10, 20, 50]regParam 取值 [0.01, 0.05, 0.1]maxIter 固定15。跑了9组实验记录 RMSE 如下rankregParammaxIterRMSE100.01151.182100.05151.074100.1151.061200.01151.145200.05150.936200.1150.951500.01151.201500.05150.968500.1150.977对比下来rank20、regParam0.05时效果最好RMSE约0.936。rank过大反而变差这是典型的过拟合特征模型把训练数据里的噪声学进去了泛化能力下降。一个肉眼可感知的规律是rank不要超过数据稀疏度的平方根太多6万评分、8000酒店这个规模20足够。5.4 冷启动问题的兜底策略ALS 只能给有过行为的用户推荐酒店但系统里难免出现新用户或评论很少的酒店。我的解法是在生成推荐列表时加一层兜底逻辑模型有推荐结果就用模型结果没有就用热门榜补位。热门榜的规则是score 4.5 且 comment_count 50的酒店按评论数降序取前20。这个兜底逻辑写进论文和答辩PPT里很有用因为老师经常追问新用户怎么办你有一个明确的工程化方案就已经超出了大多数只跑通模型的毕设水平。6. 可视化大屏指标设计、接口约定与展示技巧6.1 大屏上放什么数据才有说服力可视化在毕设里的地位非常微妙你说它技术含量高其实不高但你说它不重要绝对不行。因为答辩的时候老师最直观看到的就是大屏效果。一套好的可视化大屏要有层次全局指标、分布分析、明细排行、场景化推荐结果。我当时设计的页面分为四个区域顶部是从 Hive 汇总出来的关键数字城市总数、酒店总数、平均评分、平均价格中部左侧是城市地图颜色深浅表示该城市酒店数量多少中部右侧是价格区间占比饼图和星级酒店数量柱状图底部是推荐结果卡片区输入一个用户ID就能看到他被推荐的5家酒店每张卡片上展示酒店名、价格、评分、标签。页面核心数据来自 Hive 的 DWS 层不需要实时计算所以后端接口直接从 MySQL 读取即可。这里有个实用经验大屏上的数据不要全跑 SQL 实时聚合可以启动时加载一次 DWS 汇总表前端用 ECharts 的setOption动态更新视觉上够流畅实现也简单。6.2 后端接口与前端组件的字段约定我设计的接口就四个非常克制接口路径返回内容对应图表/api/summary城市数、酒店数、平均评分、平均价格顶部数字卡片/api/city_distribution城市名、酒店数量、平均价格地图/api/price_star价格区间、星级、酒店数量饼图/柱状图/api/recommend/{user_id}推荐酒店列表名称、价格、评分、标签底部推荐卡片接口设计的原则是一个接口对应一个图表字段控制在5个以内。不要试图做一个大而全的接口让前端自己挑数据那样联调成本会高出一倍。ECharts地图需要每个城市的地理坐标我没有用高德API而是在数据初始化脚本里内置了一份城市经纬度表因为只需要城市粒度坐标点固定就够用。6.3 让推荐效果看得见的小技巧推荐结果单纯用表格展示看不出算法的价值。我加了一个对比逻辑页面左侧显示用户的基础画像来自模拟数据的偏好字段右侧显示推荐结果。比如用户A偏好商务出行推荐卡片里的酒店就都带近地铁商务中心标签老师一看就明白推荐是有逻辑的不是纯随机。这个设计加上一句讲解词推荐结果基于ALS隐特征匹配能覆盖用户历史偏好中的关键维度整个项目的技术可信度会提升一大截。7. 集群环境与资源调优三台虚拟机的血泪踩坑7.1 单机伪分布式还是多节点集群毕设阶段最常见的环境问题是纠结要不要搭真实集群。我当时用了3台虚拟主机每台4G内存操作系统统一Hadoop版本3.xSpark 2.4Hive 3.x。三台机器分别部署为一台MasterNameNode ResourceManager HiveServer2、两台WorkerDataNode NodeManager。如果你的电脑配置不够完全可以用单机伪分布式模式跑通全流程。但有一点必须提前确认Spark的local[*]模式和 YARN 模式在代码里写法不一样。如果最终跑在集群上建议从一开始就用SparkSession.builder().appName(xxx).enableHiveSupport().getOrCreate()提交时用spark-submit --master yarn这样代码不用来回改。7.2 内存不足导致的任务失败与排查路径我遇到的最大坑是Spark任务频繁报OOM。刚开始所有配置都用默认值executor内存只有1G训练ALS时直接崩溃。排查思路是三步先看YARN日志确认是哪个Container挂的发现是executor内存溢出再把spark.executor.memory和spark.driver.memory从1g调到2g同时降低spark.sql.shuffle.partitions从200降到50最后评估数据量6万条评分数据完全不需要太多分区分区过多反而导致任务调度开销大于计算开销。还有一次更隐蔽的问题Hive 和 Spark 共用同一个 MySQL 存储元数据Spark 执行 SQL 时因为 Hive Metastore 版本不兼容报错。解决方式是统一版本Hive 3.x 对应 spark-hive_2.12 的替换包。这类问题网上资料很杂我在论文中干脆附了一个环境兼容性对照表注明Hadoop、Spark、Hive三个组件的版本组合既帮后来人避坑也让答辩老师知道你确实不是搭了个假集群。7.3 数据量估算与HDFS副本策略有个细节容易被忽略HDFS 默认副本数是3对毕设集群来说纯属浪费。我只设了副本数为2dfs.replication2既保证容错又节省一半磁盘空间。整个系统最终数据量其实很小原始CSV不到50MB加上数仓表格的副本也就几百MB跑在大数据框架上杀鸡用牛刀的感觉很明显。但你需要清楚毕设考察的是你理解了大数据框架的用法不是真的需要处理PB级数据。任务调度方面我没有上Azkaban或Oozie。原因是整个处理链路总共就几个步骤写成一个 Shell 脚本按序执行就够了。上调度框架不仅增加部署复杂度论文里还得解释框架原理性价比不高。如果你的时间比较充裕提到可以直接通过crontab定时调度每日增量数据这种方向性描述即可不需要真做实时流。8. 论文组织与答辩准备如何让三个月的成果被看见8.1 论文目录结构设计参考毕业设计论文的结构每家学校要求不一样但整体逻辑可以复用。我当时的目录是这样组织的章节内容安排第一章 绪论选题背景、国内外研究现状、研究内容与目标第二章 相关技术介绍HDFS、Spark、Hive、ALS算法原理第三章 系统需求与总体设计功能需求、架构设计、模块划分第四章 数据采集与预处理爬虫实现、字段清洗、数据质量保障第五章 数仓设计与实现ODS/DWD/DWS三层建模、建表SQL、数据说明第六章 推荐引擎的设计与实现评分构造、ALS训练、参数调优、评估结果第七章 可视化系统实现前后端方案、接口设计、页面展示第八章 系统测试与总结功能测试、性能测试、不足与展望这个目录的巧妙之处在于每一章对应一个技术模块工作量分布一目了然。答辩时老师随便从哪一章切入提问你脑子里都有对应的代码和实验数据可以直接调用。8.2 答辩现场最容易翻车的五类问题根据我自己的答辩经历和被老师追问的经验整理出高频问题清单数据哪来的合不合法回答要点公开网页的公开信息遵守robots协议设置了合理访问频率仅用于学术研究。千万不要说爬了某个平台全部数据这种话。为什么用ALS不用别的算法回答要点ALS在稀疏矩阵上表现稳定Spark MLlib原生支持训练效率高同时可以一句话带过如果追求更高精度可以考虑基于内容的推荐或深度学习模型但毕设场景下ALS在效果与实现成本之间最平衡。把可行性放在第一位是工程思维的体现。用户评分是模拟的推荐效果怎么算真实回答要点明确区分数据真实性和技术可行性说明系统重点在于验证从数据采集到推荐展示的完整技术链路且模拟数据按照业务规则生成、加入噪声保证分布合理模型评估用RMSE等量化指标证明算法收敛。Hive和Spark的分工在哪里体现回答要点Hive负责离线数仓建模和指标统计Spark负责复杂的迭代式计算和模型训练。如果两者角色互换Hive跑ALS算法非常困难Spark做SQL数仓加工不如Hive直观。性能上各干各的才是最优。如果要做成实时推荐怎么改回答要点把离线ALS改成增量更新引入实时日志采集评分流进入消息队列由流计算引擎更新用户隐特征。这个问题的关键是让老师知道你对实时架构有概念而不是真的让你现场改代码。8.3 演示脚本的顺序安排最后建议准备一份固定的演示流程控制在8分钟以内。我的顺序是先从爬虫产出的CSV讲起打开Hive运行一条SQL展示数仓数据然后切到Spark训练日志展示RMSE结果最后打开可视化大屏输入用户ID展示推荐结果。整个流程从数据源头到最终展示完整串联每一步都有现场操作或截图佐证。不要一上来就讲概念和技术原理等演示完再配合PPT补理论部分老师的注意力已经被真实数据流动吸引住了后面的原理反而听得进去。这段内容做完之后整个系统从采集到推荐再到展示就是完整的闭环。最后分享一个实际体会工程记录本从项目第一天就要开始写每天记录进度、遇到的问题、解决思路。写论文时你会发现那些碎片记录比任何回忆都可靠答辩时老师问遇到的最大困难是什么你也可以直接翻出记录里最真实的一页作答不用现场编。这个习惯比多写一百行代码都值钱。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询