尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Hadoop与Spark的酒店推荐系统:从爬虫到可视化全链路实践

基于Hadoop与Spark的酒店推荐系统:从爬虫到可视化全链路实践 毕业设计还没头绪的话这套链路可以直接抄。Hadoop、Spark、Hive、推荐系统、爬虫全串起来做酒店推荐系统从数据采集到可视化每一步都有成熟方案能跑通、能答辩、能写进简历。关键在于理清数据流向和模块边界。先看整体架构再逐个拆解实现细节。1. 整套系统的架构拆解数据流决定代码结构先别急着写代码把架构图画清楚比什么都重要。我这套酒店推荐系统走的是标准离线数仓路线爬虫采集数据结果落HDFSHive做清洗和加工Spark负责特征计算和推荐模型训练最后结果回写MySQL供Web端展示可视化报表用ECharts渲染。技术栈选型的核心逻辑说透一点。Hadoop提供HDFS存储底层数据这是所有计算的基石Hive把HDFS上的结构化数据映射成表用SQL方式做数据清洗开发效率远高于手写MapReduceSpark则从Hive中读取加工后的数据跑推荐算法和统计计算速度比MapReduce快几倍到几十倍。三者配合各取所长这是大数据离线处理场景的经典组合。整个数据流就两条线。一条是主链路爬虫抓取酒店数据写入HDFS原始目录Hive建外部表映射原始数据然后通过SQL完成清洗转换生成标准宽表Spark从宽表读取数据训练模型并计算统计指标最终结果写入MySQL和Redis。另一条是支撑链路定时调度脚本串联每个环节日志监控记录每个任务的运行状态出错时自动重跑或报警。这个架构最值得学习的地方在于解耦。爬虫、数仓、推荐、可视化四部分之间只通过数据交互互不依赖。爬虫挂了不影响推荐模块运行推荐模型重训不影响可视化展示。这一点在答辩时特别有用老师问某个模块挂了会怎样你可以明确回答各模块独立运行、互不干扰。对于一个人完成的毕业设计来说这个架构不会让你疲于奔命数据从源头到展示每个环节都有明确的产物和验收标准。模块规模控制得当整套系统不是瘫在那里——爬虫模块抓取几万条真实酒店数据Hive数仓建好分层表结构Spark训练出推荐结果并统计各种指标Web可视化面板把结果全方位呈现出来。模块的具体划分和每部分的职责可以在表格中清晰对比模块技术实现输入数据输出产物数据采集Python Scrapy公开酒店信息JSON数据文件分布式存储HDFSJSON数据文件原始数据落盘数据仓库HiveHDFS原始数据清洗后的标准宽表离线计算SparkHive宽表推荐结果、统计指标数据服务MySQL RedisSpark计算结果推荐列表、指标数据可视化展示SpringBoot EChartsMySQL接口数据Web大屏和推荐页面看到这个分工你就能明白准备工作该做什么了。如果你还在纠结用什么技术而不是怎么组装技术那现在开始调整思路围绕数据流来做设计代码才有方向。2. 爬虫采集模块别只会用requests工程化才是关键酒店数据是整套系统的源头数据质量直接决定推荐效果。很多同学写爬虫就是requests加BeautifulSoup抓几页就完事了作为毕业设计这远远不够。你要展示的是工程能力不是仅仅能拿到数据。2.1 技术选型为什么用Scrapy而不用requests单机爬虫用requests完全够用但工程化爬虫必须上框架。我选Scrapy的理由很实在并发抓取、自动限速、断点续爬这些功能是自带的不需要自己造轮子。对于酒店数据几百个城市的采集需求单线程跑要几个小时Scrapy开8个并发半小时搞定。Scrapy的架构也要能说清楚Item Pipeline处理数据清洗和去重Downloader Middleware处理请求重试和代理切换这两个组件在答辩时被问到的概率极高。数据清洗逻辑写在Pipeline里比如统一价格格式、过滤无效经纬度反爬策略写在Middleware里比如随机User-Agent、访问间隔控制。核心爬虫代码的结构大致是这样我简化了细节主要是让你看整体架子。第一个是爬虫主体通常放在spiders/hotel_spider.py里关键参数解析在parse方法中完成第二个是数据管道也就是pipelines.py负责清洗、格式化和落盘第三个是配置管理settings.py里的并发数、下载延迟、日志级别都统一在其中配置。2.2 反爬策略与数据结构设计避免最常见的几个坑酒店类网站的反爬相对温和主要就是检查User-Agent、请求频率和IP访问量。应对策略就是三件套随机User-Agent伪装浏览器、Downloader Middleware中控制请求间隔、IP池备用。最需要注意的其实是数据字段设计。推荐的酒店数据至少包含这几个维度酒店名称、城市、星级、价格区间、评分、评论数、经度纬度、酒店类型、设施服务列表。经纬度是必须有的后面做城市维度的推荐和可视化时它能派上大用场。抓下来的数据存成JSON Lines格式每行一条记录这样即使中途停止也能从上次位置继续爬。后端的Hive表结构设计也围着这些字段走我直接建表时就按照JSON嵌套的方式做了预处理能存下整个设施列表。2.3 爬虫模块的验收标准爬虫不是抓了数据就完事你要定好验收标准。数据量级多少合适字段覆盖率多少合格数据格式是否统一。我给自己定的标准是抓取至少10个主要城市、每个城市100家以上酒店字段完整率超过95%日期和价格字段格式统一无异常值。如果你想要更好的数据展示效果在爬取酒店基本信息之外还可以把酒店的评论摘要、评分分布等数据一并采集下来这些在数据分析阶段都是很好的素材。调研了几个酒店数据源后发现直接用主流的公开酒店信息平台作为数据源最稳定不用签名、不用复杂加密只做基础的反爬处理就能获取到数据。数据覆盖多个城市、包含价格评论等字段。3. Hive数据仓库分层从原始数据到标准宽表爬虫只是开始真正的重头戏在Hive数仓这一层。如果说爬虫决定了项目的下限数仓设计则决定了项目的上限。这部分做好了后续的Spark计算和可视化才能顺畅运行。3.1 数仓为什么要分层ODS、DWD、ADS三层设计设计数仓分层时我建议直接用经典的三层结构。ODS层存放原始数据也就是从HDFS上加载进来、未经过任何处理的JSON内容DWD层做清洗和转换统一字段格式、过滤异常数据、拆分JSON字段ADS层汇总统计结果供上层应用使用也就是根据业务需求预计算指标。为什么非要分层核心原因有两点。一是避免重复清洗原始数据的问题在DWD层一次解决后续不管是推荐还是统计拿到的都是干净数据。二是便于回溯线上数据出问题时可以从ADS逐层往下排查精确定位是哪个环节出了问题。Hive建表时要给每一层明确命名规范看表名就知道数据在哪一层做什么。ODS层表名以ods_开头DWD层是dwd_ADS层是ads_。不要觉得多此一举等你的表多起来后没有命名规范根本没法管理。3.2 建表语句的细节处理ODS层建表使用外部表这样删除表时不会误删HDFS上的源文件。字段设计上用string接收原始字段等到清洗阶段再转类型避免JSON解析失败导致加载失败。关键建表语句是在创建外部表时用row format serde指定JSON格式解析。这个操作本身不难但它决定了后续所有数据能否被正确识别值得花时间反复测试。DWD层真正开始干活通过insert overwrite的方式从ODS读取数据完成清洗转换。清洗逻辑包含过滤掉非目标城市的冗余数据、拆分价格字段去掉货币符号、将经纬度字段统一格式、解析JSON数组得到设施列表。每次执行后对结果做一次count和样例抽查确认数据质量没问题再继续。ADS层则是一切指标的汇总出口同时服务于推荐系统和可视化。比如城市维度的酒店数量、评分均值和价格分布可以直接为可视化面板提供指标数据。而用户维度、酒店维度的特征数据则为推荐系统持续供数。3.3 数据倾斜和小文件问题前期就得留个心眼Hive跑数仓任务时的几个坑值得提前说清楚。数据倾斜是其中最常见的比如统计某个大城市数据时如果按城市聚合大城市数据量远大于其他城市就会导致reduce阶段某个节点拖后腿。解决方案是先做随机前缀打散再二次聚合把倾斜的数据分散到多个节点。另一个问题是小文件过多。ODS层如果直接load爬虫抓的JSON文件数量可能很多但单个文件很小会导致Spark读取时频繁切换任务性能急剧下降。解决办法是在清洗前先做一次输入合并用Hive的concatenate命令合并小文件或者用distribute by rand()做一次重分区。环境准备还有个小提醒Hive on Spark模式下需要保证Hive和Spark版本兼容否则会出现各种诡异报错这类问题排查起来相当耗时。确定版本兼容方案之后先把临时搭建的配置记录下来重装时能快速复现。这里更推荐Hive on Tez引擎跑起来更稳定测试省心。我早期用MapReduce跑清洗任务一个简单的聚合等了几分钟换成Tez后速度快了一个量级是值得牢记的教训。4. 推荐系统核心算法协同过滤的原理与代码落地这一部分是整个系统的灵魂也是答辩时老师最关注的地方。很多同学看到推荐系统四个字就害怕其实实现一个算法原型并不难难在把原理讲清楚、把流程跑通。4.1 选择协同过滤而不是深度学习的原因深度学习模型效果通常更好但需要大量训练数据和算力毕设周期内很难整出效果。而协同过滤作为推荐系统的经典算法原理清晰、实现简单、开箱即用完全足够支撑毕设的体量。酒店推荐场景跟电影推荐还不太一样。酒店消费频次低用户行为数据稀疏用基于物品的协同过滤比基于用户的协同过滤更合适。基于物品的思路是如果用户A住了酒店X和Y用户B住了酒店X就给B推荐Y。实现起来简单直接。基于物品的协同过滤分为三个步骤计算酒店间的相似度矩阵、找出用户历史浏览过的酒店、根据相似度给出Top N推荐。具体计算时酒店间的相似度用余弦相似度代码实现不复杂但每个步骤都要能讲清楚。4.2 Spark MLlib的实现方案使用Spark MLlib中的ALS算法做矩阵分解这是业界最成熟的方案之一。ALS的输入是一张用户行为表包含userId、hotelId、rating三个字段输出是每个用户的向量表示和每个酒店的向量表示两者相乘就得到预测评分。在ALS的实际应用过程中rating的构造可以结合业务逻辑确定一个合理规则。具体做法可以参考浏览记1分收藏记3分预订记5分这样既覆盖了不同强度的用户反馈也能保证数据有一定的区分度。如果数据量少还可以适当放宽行为记录的时间窗口期比如保留最近一年的记录增加训练样本数量。模型调参也是重中之重ALS有3个参数直接决定推荐效果。rank是隐语义因子的个数取值范围一般是10到50在酒店数据集上rank20可以取得较稳定的效果。iterations是迭代次数正常情况下10次就能收敛设置过多只会拖慢训练速度。lambda是正则化参数用于防止过拟合默认0.1够用。调参的方法不要靠感觉。把训练集和验证集按8比2划分固定其他参数只调整一个参数观察推荐效果评估指标用均方根误差哪个参数组合的误差最小就用哪个。4.3 推荐结果落地从Spark到MySQL的完整链路训练好的模型需要生成最终的推荐列表再写回MySQL供Web端查询。链路是这样的先从Hive宽表中读取用户行为数据、从酒店表中读取酒店信息训练ALS模型后对每个用户生成Top N酒店推荐列表然后写入MySQL的表里。如果嫌ALS步骤复杂还有一条更快的路直接用Spark SQL做基于规则的推荐。比如跟该酒店同城市、同星级、评分相近的酒店就是一种有效且容易解释的推荐逻辑一条SQL就能搞定。这种方式虽然学术价值有限但工程逻辑清晰答辩时照样能讲得头头是道。真正的实战过程建议先从规则推荐起步跑通全链路后再换ALS模型提升效果。这样既有baseline又有进阶答辩时的发挥空间就出来了。推荐模块代码的入口一般是这样组织的先配置SparkSession和读取hive表的基础环境再做ALS模型训练和保存结果操作。这个框架无论在规则推荐还是ALS的场景下都适用。5. 可视化展示层ECharts大屏和推荐页面这样搭整个系统做得好不好老师第一眼看的是可视化效果。页面漂亮与否直接影响第一印象所以这一块要花时间打磨。5.1 可视化大屏的指标设计可视化大屏的核心指标要围绕数据价值和业务场景来选。酒店总数、覆盖城市数量、平均价格、评分分布这4个KPI指标体现在大屏顶部一眼就能看出数据全貌。地图展示酒店在不同城市的分布情况用ECharts地图组件点击可下钻到省份查看城市数据。价格和评分的分布则用直方图和散点图呈现。指标数据从哪里来从ADS层去取。比如酒店总数就是select count(*) from ads_hotel_city_stats平均价格是select avg(price) from ads_hotel_stats。你要把这些查询逻辑封装成Mapper接口通过SpringBoot的Controller暴露给前端。5.2 可视化大屏的开发顺序我开发大屏时的顺序供你参考先确定页面布局草图规划上下左右分别放什么图然后写后端接口返回JSON数据接着用ECharts官方示例改造出需要的图表类型最后把所有图表和数据拼接到大屏页面。后端接口的返回格式建议统一为{code, data, msg}结构前端拿到data直接渲染。接口开发时要考虑数据异常的情况比如数据为空时返回空数组前端做对应的empty处理。地图数据需要注意从ECharts官方下载中国地图的GeoJSON文件还有对应各城市坐标的配置。5.3 推荐页面如何展示推荐结果推荐结果页固然是给用户看推荐列表但毕设系统的评判对象其实是老师。所以页面要能解释为什么推荐这个酒店给你。推荐结果页展示的不仅仅是酒店卡片列表更要有推荐理由。如因为您浏览过杭州西湖附近的X酒店所以为您推荐同区域、同价位的Y酒店这个理由一方面让推荐不那么生硬另一方面也确实体现了系统背后的推荐逻辑。前端调用推荐接口的交互方式实际不复杂用户登录后后端根据userId调用推荐服务接口返回推荐列表前端渲染卡片并在卡片下方展示推荐依据。这样整个交互闭环就完整了。6. 环境搭建中最容易翻车的几个地方环境搭建是整套系统最磨人的阶段有些问题能查一天都不一定有结果。我把个人踩过的几个高频坑集中列出来希望能帮你提前规避。6.1 版本不兼容是万恶之源大数据组件版本之间互相兼容的关系非常微妙Hadoop和Spark之间、Hive和Spark之间都有明确的版本配套要求。很多同学一上来就装最新版结果要么编译报错要么运行时各种NoSuchMethodError最终浪费大量时间。建议直接参考官方文档对应的版本矩阵选套餐稳妥省心。我实际用的版本搭配是Hadoop 3.3.4、Spark 3.3.2、Hive 3.1.3。这三个版本在兼容性测试中表现稳定网上资料也最多出bug搜得到解决方案。6.2 虚拟机内存分配要提前规划毕设的整套环境至少需要三台虚拟机来搭建集群。每台虚拟机分配内存至少4GB总共至少12GB内存。如果电脑内存只有16GB建议把资源调优NodeManager的内存参数调小Spark Executor内存控制在1GB左右否则集群启动后电脑基本卡死。如果确实资源不够也可以采用本地伪分布式模式跑通全流程。但要注意伪分布式和真集群在HDFS块复制、ResourceManager调度等细节上有差异实验做完后要在文档里说明清楚。6.3 网络配置和SSH免密登录集群中主机名、IP、端口的配置是另一个报错高发区。每台机器修改主机名、配置/etc/hosts映射关系并配置SSH免密登录确保Master节点可以无密码登录所有Worker节点。做完后务必用ssh命令逐个验证因为很多服务启动时都要通过主机名进行通信。6.4 日志排查比瞎猜重要得多服务启动失敗时的排查思路太关键了。第一步先看日志Hadoop的、Spark的、Hive的日志文件里都记录了明确的报错信息。第二步根据报错关键词搜索百分之八十找不到解决方案是我的错觉实际上能搜到的概率有百分之九十。第三步才考虑环境层面的问题比如内存分配、目录权限等。7. 答辩演示的准备与技巧答辩和做项目是两个能力维度。做项目是能把技术栈跑通答辩是能把技术栈讲清楚。很多同学项目做得很好一到答辩就语无伦次核心原因在于没有提前准备。7.1 演示前的数据准备演示前要保证数据量和数据质量都处于最佳状态。数据量太少可视化大屏会显得很空数据异常太多会影响演示效果。建议准备一次完整的数据刷新流程在演示前把最新数据灌进去确保大屏上展示的数字清晰、图表完整。7.2 讲解话术的组织逻辑讲解话术要按数据流顺序来组织从项目背景、架构设计、数据采集、数仓处理、推荐算法、可视化展示到总结展望形成一条完整的逻辑线。每个环节都要准备一页PPT和对应的讲解要点控制在15分钟之内讲完。针对每个模块还要提前预设老师可能追问的问题。例如数据源是什么、爬虫效率如何、为什么选这些算法、数据量级多大等。准备充分不仅是为了答辩从容也是在帮自己理清项目思路。7.3 讲解过程中一定要避开的几个坑第一不要吹数据量。一个毕业设计的数据量说实话就好老师不会因为数据量小就否定你反而会因为你诚实和有条理而给高分。第二不要回避问题。不会的就说这块我主要是参考框架实现原理部分我还需要进一步学习诚恳比硬撑要好。第三不要背PPT。讲的时候要和PPT内容有互动该切系统演示就切系统演示不要全程站在屏幕前不动。8. 项目代码的工程化管理与后续优化方向代码管理是容易被忽视的一项。整套系统涉及多个模块如果不用Git管理版本混乱只是时间问题。建议用Git记录每个阶段的成果例如爬虫模块完成后打一个tag数仓建表完成后打一个tag推荐模块跑通后再打一个。这样出了问题能迅速回滚写论文时也好回顾每个阶段的进度。项目目录结构的规划也要提前设计清楚用表格展示更加直观模块目录核心文件爬虫crawler/spiders/hotel_spider.py, pipelines.py数仓hive/ddl.sql, etl.sql, ads.sql推荐spark/als_train.py, rule_rec.py, data_export.py后端web/controller/, service/, mapper/前端web/frontend/index.html, echarts/后续在这个框架上值得拓展的方向主要有几个。冷启动问题的优化是重点新用户没有行为数据时可以用基于规则的热门推荐做冷启动这个思路可以单独当一节写进论文。实时推荐也是一个方向用Spark Streaming消费用户实时行为数据与离线推荐结果做融合。图谱增强推荐的想法则是在现有数据基础上增加酒店周边的兴趣点属性例如景区、商圈、地铁站等可以按照用户出行的偏好做更细粒度的推荐。维护这套系统过程中我体会最深的一点是大数据真正难的从来不是调API和写SQL而是数据质量。数据质量不过关后面所有算法和可视化都是空中楼阁。所以别急着上模型先把数据管好推荐效果自然就来了。
返回列表