ARTICLE DETAIL

资讯详情

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

Python+Hive酒店数据分析与推荐系统毕设全流程实战

Python+Hive酒店数据分析与推荐系统毕设全流程实战 每年到这个时候总有一堆学弟学妹私信我问“毕设做什么方向好”“有没有现成的源码参考”。如果你对大数据、数据分析、推荐系统这套技术栈感兴趣又不想做那种纯理论、没法演示的题目这个项目可以重点研究一下。Python基于Hive数据仓库的酒店数据分析与推荐系统名字听着长本质上就是把当下企业里最常用的几个技术点——Hadoop生态里的Hive数仓、爬虫采集、协同过滤推荐、Django后端、Vue可视化——全部串到一条完整的数据链路上。整个项目面向酒店、民宿、客栈这类住宿数据从采集公开数据、清洗入库到离线分析、算法推荐再到前端大屏展示全程可以跑通答辩的时候从数据流讲到算法细节再现场演示界面内容非常能打。我当时帮人调试过好几个类似的项目也踩过不少坑这篇文章就把整套东西从架构设计到落地实现、再到答辩避坑完整拆开讲清楚适合正在选毕设题目、或者已经选了类似题目但不知道从哪下手的同学收藏。1. 先理清楚这个毕设到底要做什么1.1 项目的核心目标和功能模块很多人拿到这种题目容易迷茫因为关键词太多了Hive、Django、Vue、Hadoop、爬虫、协同过滤、酒店数据分析、可视化……听着像要同时做五个项目。其实你拆开看就是一个完整的“数据产品”的五层结构数据采集层用Python爬虫从公开的OTA平台比如携程、去哪儿、美团这类网站上对外展示的酒店信息抓取酒店、民宿、客栈的基础信息包括名称、价格、评分、评论数、地址、经度纬度、设施标签等。数据仓库层把爬下来的原始数据先落一份原始备份再通过Hive做数据清洗、转换、建模形成面向分析的主题表供后续查询统计。离线分析层基于Hive SQL跑各类分析指标比如各城市的酒店均价、价格区间分布、评分分布、评论量Top榜、不同档位酒店的数量对比等。推荐引擎层基于用户行为数据比如用户浏览过哪些酒店、收藏过哪些、评分打几分使用协同过滤算法生成个性化推荐列表。展示层Django作为后端提供APIVue ECharts作为前端做可视化大屏和推荐结果展示。说白了这就是一个“采集—存储—分析—算法—展示”的闭环。你看这个结构就明白它不是让你把某一个技术做得特别深而是要求你把每个环节都打通整体呈现一套工程化能力这正是毕设最看重的。1.2 技术选型为什么这么组合先解释一下这个技术栈组合的逻辑因为很多人不理解“为什么非要用Hive”。先说Hive。酒店数据量大不大说实话你爬个几万条数据用MySQL也完全能存。但Hive的价值在于它是数据仓库的经典技术方案跑的是SQL-on-Hadoop底层计算引擎是MapReduce或者Tez它代表的是大数据离线处理的标准思路。毕设用Hive不是为了“存不下”而是为了展示你懂数仓建模、懂HQL分析、懂Hadoop生态。而且Hive的表结构设计、分区策略、数据装载这些知识点面试也常问一举两得。Django主要负责业务层和接口层。Python在数据领域生态最好Django又是Python Web框架里最成熟、文档最全、自带Admin后台的。你不需要额外写太多胶水代码把分析结果或者推荐结果通过ORM查出来然后用DRFDjango REST Framework序列化输出JSON前端直接消费非常顺畅。Vue这边的定位是“轻前端”。如果你的前端功底一般Vue比React更好上手而且配合ECharts做可视化图表一段配置就能画出柱状图、饼图、地图、雷达图视觉效果好答辩时演示很加分。1.3 整体架构和数据流向我直接按数据流向给你梳理一遍这套逻辑你写进论文“系统架构”那一章完全够用爬虫程序从OTA平台抓取酒店公开信息生成结构化JSON或者CSV文件同时备份一份到MySQL方便后续Django直接读取展示。把清洗后的数据文件上传到HDFS在Hive中创建外部表完成数据装载。在Hive里对原始表做ETL生成DWD明细层表和ADS指标层表跑各种统计SQL结果导出到MySQL中的分析结果表。用户行为数据评分记录进入协同过滤算法模块用Python离线计算用户相似度矩阵或者物品相似度矩阵生成每个用户的TopN推荐列表写回MySQL。Django后端从MySQL读取分析结果和推荐列表暴露RESTful API。Vue前端调用Django接口用ECharts渲染可视化看板同时展示针对当前用户的酒店推荐卡片。这套流程里你最需要注意的是Hive是“离线批处理”的思路它算完结果后要落到MySQL里供Web系统查询。很多人一开始想把Hive直接当数据库用让Django直连Hive那样会又慢又别扭正确的做法就是“Hive算完MySQL查”。2. 爬虫采集与数据预处理2.1 采集目标与字段设计爬虫这部分目标很简单拿到足够多的酒店/民宿/客栈数据并且字段要能支撑后续的分析和推荐。我建议字段至少包含这些酒店基础信息酒店ID、名称、城市、行政区、详细地址、经度、纬度、酒店类型酒店/民宿/客栈、星级或档次标签。价格与销量最低价格、最高价格、评分、评论数、销量或预订量。设施服务是否含早餐、免费停车、健身房、游泳池等布尔型标签可以转成多值字段。用户关联数据如果你的系统要做协同过滤推荐还需要模拟或者真实采集一部分“用户行为”比如用户ID、酒店ID、评分1-5分、评论内容、浏览时间。很多同学纠结“我没有真实用户数据怎么做推荐”我的建议是自己构造一份比较合理的行为数据集。比如设定50个虚拟用户让每个用户对10到20个酒店有评分行为评分分布符合常理高分集中在评分本身高的酒店低分分散然后再结合爬到的酒店特征做协同过滤。只要在论文里说明是“为演示推荐流程而构造的用户行为数据集算法验证在公开数据集上也跑过”这个点就能站得住。2.2 爬虫实现的关键点爬虫核心无非是requests/Selenium BeautifulSoup/正则。但有几个实操细节直接决定你能不能顺利爬到数据我一个个说。第一请求头必须伪装完整。很多反爬检测看的是User-Agent、Referer、Accept等头部是否像真实浏览器。你光设一个User-Agent不够最好直接从浏览器复制完整的请求头。另外建议使用requests.Session()保持会话模拟真实用户的浏览行为。第二控制请求频率。千万别用单线程连环请求酒店平台的风控不是吃素的。我实测下来每秒1到2个请求每爬500条休息十几秒比较稳妥。如果规模再大一点就用time.sleep加随机抖动避免访问频率形成固定规律。第三如果页面数据不是一次性渲染出来的比如详情页是异步加载直接抓HTML拿不到价格和评分这时候用浏览器开发者工具看Network里的XHR请求找到真正返回数据的JSON接口直接请求那个接口解析JSON比自己抠HTML要靠谱得多。第四数据清洗要在爬虫端先做一道。比如把价格里的“¥”和“起”去掉把“5.0分”转成浮点数5.0把地址中的空格和换行清除经纬度如果是字符串要转成float。这些写在解析函数里一步到位不然爬到后面再回头清洗就很麻烦。这里多说一句题外话爬虫只是做技术验证抓取范围控制在公开内容、有限规模、学习研究用途并且严格遵守目标网站的服务条款和访问频率限制别做大规模商业抓取这是底线。2.3 数据清洗与存储策略清洗这一步看似不起眼但直接决定Hive查询结果的准确性。酒店数据最常见的问题就是脏数据比如价格字段有“暂无报价”或者空值需要过滤或填充。评分字段出现“暂无评价”这样的文本。城市字段同一城市有不同写法比如“北京”和“北京市”并存。重复数据同一家酒店爬了两次需要按酒店ID去重。清洗思路是写一个独立的Python脚本读取原始爬取文件做去重、类型转换、缺失值处理然后输出两个文件一个是清洗后的酒店明细表另一个是用户行为表包含用户ID、酒店ID、评分、时间戳。存储方面建议做双写策略一份存MySQL给Django展示和推荐系统实时读一份存本地CSV用于后续上传HDFS进Hive。这样既保证Web端查询快又能体现“数据进数仓”的完整流程。MySQL中建两张核心表一张hotel_info一张user_ratingDjango的model和它们对应后面开发会非常省事。3. Hive数据仓库搭建与离线分析3.1 Hadoop与Hive环境准备如果你用的是发行版比如HDP、CDH环境会简单一些但毕设一般建议直接用Apache Hadoop Apache Hive手动搭建这样既省钱又能把所有配置写进论文。Hadoop我建议用伪分布式模式就是一台机器上同时跑NameNode、DataNode、ResourceManager、NodeManager这几个进程。虽然生产环境都是集群但毕设演示伪分布式足够而且能完整体现HDFS的存储机制。配置文件主要是core-site.xml、hdfs-site.xml、yarn-site.xml这几个核心就是把fs.defaultFS设成hdfs://localhost:9000把副本数设成1然后格式化NameNode再启动。Hive的话重点在于Metastore的配置。初学者最容易踩的坑就是没配好Derby或者MySQL作为元数据存储导致启动Hive时报错“javax.jdo.JDOFatalInternalException”。我建议直接把Hive的元数据库配到MySQL用起来稳定重启不丢元数据。关键是在hive-site.xml里配好javax.jdo.option.ConnectionURL和驱动。如果你的Win环境跑不起来Hadoop那就装个虚拟机在Ubuntu Server上部署把快照打好后面出问题随时回滚。网上搜“hadoop伪分布式搭建”和“hive的安装与配置”照着做基本都能跑通。3.2 数仓分层建模Hive建表最能体现你有没有数仓思维不要上来就建一堆平表一定要分层。我建议分三层ODS层原始数据层建外部表ods_hotel_info映射到HDFS上的原始CSV文件。外部表的好处是删除表不影响原始文件比较安全。DWD层明细数据层把ODS的数据清洗后落到DWD表dwd_hotel_detail加上ETL逻辑比如过滤无效价格、标准化城市字段、拆分设施标签。ADS层应用数据层面向具体分析需求生成指标结果表。比如ads_city_price_stats按城市统计酒店数量、均价、最高价、最低价ads_hotel_topn按评分数排序的TopN酒店。这里说一下每个表怎么建。ODS层表的字段要和原始文件列一一对上用ROW FORMAT DELIMITED FIELDS TERMINATED BY ,定义分隔符。DWD层表最好加上分区比如按城市分区这样后续分析SQL通过分区裁剪能减少数据扫描量同时也是一个能写进论文的优化点。数据装载很简单用LOAD DATA INPATH把HDFS上的文件load进ODS表然后通过INSERT OVERWRITE TABLE ... SELECT ... 做清洗生成DWD层。整个过程全用SQL完成非常好讲解。3.3 核心分析指标SQL实现分析指标这部分是答辩讲解的重点也是可视化页面的数据来源。我给你列几个高频指标和对应的SQL思路第一个城市酒店数量和均价。按city分组COUNT(*)统计数量AVG(price)求均价再按均价降序排列。SELECT city, COUNT(*) AS hotel_cnt, ROUND(AVG(price), 2) AS avg_price FROM dwd_hotel_detail GROUP BY city ORDER BY avg_price DESC;第二个价格区间分布。用CASE WHEN把价格分桶比如0-200、200-500、500-1000、1000以上每桶统计酒店数前端用柱状图或饼图展示。第三个评分与价格关系。用AVG(price)和AVG(score)做相关性观察按评分档位分组统计平均价格能看出高评分和高价之间是否正相关。第四个热门区域Top10。行政区和城市组合统计评论数之和取Top10展示适合做地图热力图。这些SQL写出来以后把结果INSERT OVERWRITE到ADS层结果表再通过Sqoop或者直接生成CSV导出到MySQL。如果不想引入Sqoop也有个取巧的办法在Hive命令行执行INSERT OVERWRITE LOCAL DIRECTORY把查询结果导出到本地目录拿到CSV后自己写个Python脚本灌入MySQL。两种方案都行第二种对初学者更友好。3.4 小文件治理与查询优化这部分属于加分项写进论文很亮眼。Hive跑批最常见的性能问题就是小文件过多MapReduce处理大量小文件时每个文件至少要一个Map任务启动开销极大。你在ETL里如果用INSERT OVERWRITE TABLE ... SELECT ...可以顺手设置合并参数SET hive.merge.mapfilestrue; SET hive.merge.mapredfilestrue; SET hive.merge.size.per.task268435456; SET hive.merge.smallfiles.avgsize16777216;意思就是Map端和Reduce端结束时都做一轮小文件合并目标是让输出文件平均大小在16MB以上合并后的文件大小控制在256MB左右。这样跑下一轮查询或者后续导出的时候效率会有肉眼可见的提升。还有几个Hive调优点值得做开启分区裁剪分区表查询时WHERE里带上分区字段、使用TEZ作为执行引擎在hive-site.xml里设置hive.execution.enginetez、对常用关联字段建分桶或者Sort Merge Bucket Join。这些你都跑通以后完全可以在论文“系统优化”章节里展开。4. 协同过滤推荐算法落地4.1 协同过滤的核心思想协同过滤是推荐系统里最经典、也最适合毕设展示的算法。它核心的想法就一句话物以类聚人以群分。基于用户的协同过滤User-based CF这么理解如果用户A和用户B之前喜欢的酒店很相似那么A喜欢而B没看过的酒店有很大概率B也会喜欢。做法是先构建用户对酒店的评分矩阵然后计算用户之间的相似度找到当前用户的K个最近邻再把这些邻居喜欢的、但当前用户没交互过的酒店按预测评分排序取TopN作为推荐。基于物品的协同过滤Item-based CF反过来如果酒店X和酒店Y经常被同一批用户喜欢说明它们相似那么喜欢X的用户也可能喜欢Y。它计算的是物品的相似度矩阵推荐时直接看用户历史喜欢的酒店有哪些相似的酒店按相似度排序推荐。毕设里我建议两个都实现然后做对比分析这样论文内容更充实。你自己的理解也会更深一层。4.2 基于用户的协同过滤实现实现User-based CF的步骤很清楚用Python的pandas就能搞定第一步构建用户-物品评分矩阵。从MySQL的user_rating表读数据用pivot_table转成行是用户、列是酒店的二维矩阵没有评分的位填0。第二步计算用户之间的相似度。最简单也最常用的是余弦相似度。公式你自己写也很容易就是两个向量的点积除以模长的乘积。在pandas里可以直接用cosine_similaritysklearn的metrics.pairwise里有现成的。第三步找邻居并预测评分。对目标用户u从相似度矩阵里取TopK个相似用户比如K10然后对u没有评过分的酒店i用这K个用户对i的评分的加权平均来预测pred(u, i) Σ(sim(u, v) * rating(v, i)) / Σsim(u, v)这里需要注意一点只有v对i有过评分才能参与计算如果没有一个人评过i那预测值直接不出来这种酒店就不进推荐候选。第四步生成推荐列表。把预测评分排个序去掉用户已经住过或者已经评分过的酒店取前20个写入MySQL的recommendation表。前端从这张表取数据渲染推荐卡片。4.3 基于物品的协同过滤与混合推荐Item-based CF和User-based CF的代码结构高度对称区别只是把矩阵转置之后做相似度计算。但它的推荐逻辑更直观也更适合电商类场景比如用户看过一家“杭州西湖边的民宿”系统就推荐“同样在西湖边、评分相似”的其他民宿。实现上你把评分矩阵转置变成“酒店-用户”矩阵然后计算酒店之间的余弦相似度。推荐时找到用户评分过的酒店列表取每个酒店最相似的TopN酒店加权汇总去重生成推荐列表。为了论文好看你可以在离线评估里做一个对比用交叉验证分别计算User-based CF和Item-based CF的RMSE或MAE看哪个误差更低。不同的数据集上两者胜负不一定你只要如实把实验结果写出来讨论一下差异原因比如“UserCF在兴趣变化快的场景更好ItemCF在物品数远小于用户数时计算成本更低”这个深度就已经超过大部分本科毕设了。4.4 冷启动与效果优化推荐算法最怕的就是冷启动。新用户没有任何行为数据协同过滤算不了新酒店没人评分也没法被推荐。你可以在系统里加一个简单的“热度推荐”兜底新用户没有行为数据时直接推荐评论数最多、评分最高的酒店也就是统计意义上的热门榜。前端展示的时候可以加一个标签“热门推荐”从交互上看体验也很合理。此外我当时调试时还发现几个容易被忽略的细节现在写给你评分矩阵稀疏度太高时余弦相似度可能给“只有一次共同评分”的用户对打出虚高的相似度分。解决办法是过滤掉共同评分项少于3个的用户对。相似度归一化。算出来的相似度值域可能差异很大最好对相似度做Min-Max归一化再参与加权预测不然预测值容易集体偏高或偏低。离线评估一定要做。把用户行为数据随机拆成训练集和测试集比如80%训练20%测试在测试集上算RMSE让推荐效果有数字支撑。不建议只做demo然后说“效果好”答辩老师一追问就露怯了。5. Django Vue 可视化平台开发5.1 Django后端接口设计Django这部分项目结构建议用官方推荐的分层方式一个project下面建两个app一个叫analysis负责提供统计图表数据接口另一个叫recommend负责推荐相关的接口。这样代码职责清楚答辩讲解也方便。models.py里要建和MySQL对应的模型最核心的是HotelInfo和UserRating两张表。用Django ORM查数据非常省事比如查各城市酒店均价一条ORM聚合就把活干了。接口设计遵循RESTful风格给Vue前端提供JSON。我建议装djangorestframework然后用serializers序列化Model数据。比如酒店列表接口class HotelSerializer(serializers.ModelSerializer): class Meta: model HotelInfo fields all视图里用ListViewqueryset从HotelInfo取再加上filter_backends和filterset_fields分页一开前端做筛选就很方便了。分析接口也类似比如城市价格分布接口从MySQL分析结果表读数据按城市返回价格区间、平均价、酒店数。跨域问题一定要提前处理Django跑在8000端口Vue跑在5173端口两边域名不一样浏览器会拦截请求。解决方案就是装django-cors-headers在settings.py里配置CORS_ALLOWED_ORIGINS把前端地址加进去。这个坑几乎人人都会踩别等到联调时才一脸懵。5.2 Vue前端与可视化图表Vue端的技术要求其实不高核心就是“会用Vue组件化思想组织页面 会配ECharts”。我建议直接用Vue CLI或者Vite脚手架创建项目装好vue-router、axios、echarts这三个依赖就可以了。页面结构可以做成三块概况看板放几个核心指标卡片总酒店数、平均价格、最高评分、总评论数下面俩图表一个是“城市酒店数量Top10”柱状图一个是“价格区间分布”饼图。区域分析页一个中国地图热力图展示各城市酒店密度点击城市下钻看该城酒店列表和详细统计。推荐展示页根据当前用户ID请求Django的推荐接口展示TopN推荐酒店卡片卡片带酒店图、价格、评分、标签还有“为什么推荐”的解释性文案比如“因为您喜欢西湖周边的民宿”。图表实现上ECharts只需要在mounted钩子里初始化echarts.init然后setOption。图表数据从axios请求拿到后动态填入option再setOption刷新。如果你觉得手动维护option太繁琐可以用vue-echarts封装一层把option作为prop传进去代码会更干净。5.3 前后端联调与部署联调时最烦的问题就是接口地址写死。建议在Vue项目的.env.development里配置API_BASE_URLaxios的baseURL取这个环境变量后端地址变了只改一个文件。开发模式下Vue CLI自带代理转发在vue.config.js里把/api前缀的请求代理到localhost:8000这样前端代码里就写相对路径不用处理跨域。如果你要打包部署步骤也很简单前端npm run build生成dist目录Django里配置静态文件路径把dist指过去然后用Django直接托管静态资源。或者更简单的方式把dist放到Django的static目录写一个TemplateView指向index.html。这样整个系统可以以Django为单一入口跑起来演示时不用开两个终端窗口效果更好。不过这里有个坑要提醒Vue是单页应用刷新的时候如果直接访问某个前端路由比如/recommendDjango那边没有对应路由会报404。解决办法是给Django加一个URL规则把前端路由的路径都指向那个TemplateView或者让Vue用hash模式的路由history: createWebHashHistory()。对这个项目来说用hash路由是最省事的解。6. 高频问题与答辩避坑实录6.1 环境配置高频问题这几年帮人调试这类项目环境配置阶段的问题是最多的而且翻来覆去就是那几类。第一Hadoop起不来。最常见的是NameNode格式化之后又启动报“NameNode is already formatted”。很多教程会让你先格式化再启动但如果你之前已经格式化过一次下次启动前就不要重复格式化否则NameNode的clusterID和DataNode不一致会一直报错。解决办法是把HDFS的tmp目录删掉从头格式化一次再启动。第二Hive连不上元数据库。如果你用了MySQL做Hive的Metastore报错多半是“Unable to instantiate org.apache.hadoop.hive.metastore.HiveMetaStoreClient”。这时候先排查MySQL是否能连上再检查hive-site.xml里驱动类名和连接URL最后看MySQL里hive用户是否授权了。一个常见坑你在hive-site.xml里写了“localhost”当JDBC地址但Hive服务和MySQL在同一台机器上也分情况建议直接用127.0.0.1避免主机名解析问题。第三Python和Django版本不匹配。Django新版本对Python版本有要求比如Django 4.2要求Python 3.8以上Django 5.0要求3.10以上。建议用conda建一个虚拟环境Python 3.9配Django 3.2或者4.2这样最稳。裸机装环境出各种奇怪问题真的是年轻人才受得住的罪。6.2 项目运行中的典型报错爬虫阶段遇到最多的请求返回403。这基本就是被反爬拦截了先检查User-Agent再降低请求频率实在不行就加随机延时和重试机制。我用过的最稳方案是把常用的几个UA列表放数组里每次请求前random.choice一下。Hive阶段遇到最多的LOAD DATA之后select查不到数据。多半是表的SerDe和文件实际分隔符不匹配。比如你用默认的LazySimpleSerDe但文件是用制表符分的那Hive会把整行当一个字段。检查一下文件实际分隔符建表时写对FIELDS TERMINATED BY对应的字符。Django阶段遇到最多的前端能打开但请求500。开Django调试模式先看控制台报错内容一般是不存在列名、ORM写错字段、或者数据库里的表和model不一致。这里有个墙裂建议改model之后一定要跑python manage.py makemigrations和python manage.py migrate别手动去MySQL里改表结构不然ORM和数据库结构不一致各种奇怪报错都是这么来的。推荐计算阶段遇到最多的结果全是NaN或者推荐列表为空。主要原因是评分矩阵全零——说明用户行为数据里没有匹配到酒店ID或者矩阵转置后维度不对。检查一下user_rating表里hotel_id是不是真的能在hotel_info表里join到。我调试时还碰过相似度矩阵对角线全1、非对角线全0的情况这就是数据太少导致的“所有用户之间没有共同评分”可以把行为数据再补一些让每个用户平均至少有10条评分记录。6.3 答辩演示的重点与讲解思路答辩演示环节要突出“链路完整”不要只讲UI和代码。我会建议你把现场演示按这个顺序走一遍先展示爬虫模块的代码和采集结果文件说明采集字段、清洗逻辑、数据量规模。打开Hive命令行跑几条核心分析SQL展示结果说明数仓分层和查询结果如何进入MySQL。打开Django后台或者API文档页面展示接口返回的JSON数据证明“数据链路是通的”。展示Vue可视化看板把前端图表和你刚才在Hive里跑的SQL结果对应起来让老师看到“图表数据确实来自Hive分析”。最后展示推荐结果输入一个用户ID展示推荐列表然后结合协同过滤原理现场解释“为什么给这个用户推荐这几家酒店”。答辩时老师最爱问的其实就几个问题Hive和MySQL的区别是什么协同过滤冷启动怎么解决你们的数据量多大算法评估指标是多少每个问题前面都已经有对应内容你只要把“离线计算、在线查询”这个架构逻辑讲清楚把RMSE数值张口就来基本的从容就有了。最后再说一个很多同学会忽略的细节答辩现场的演示环境一定要提前两天完整跑一遍流程包括Hadoop、Hive服务重启、Django启动、Vue打包。我曾经见过现场Hive服务起不来老师让我直接展示论文中的截图场面一度很尴尬。你把所有服务开机自启配好或者写一个一键启动脚本到时候能省去大量手忙脚乱的时间。
返回列表