ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于大数据的共享单车数据分析与可视化实战:Spark处理千万级骑行数据

基于大数据的共享单车数据分析与可视化实战:Spark处理千万级骑行数据 毕设选题那会儿我导师扫了一眼我的备选清单问了一句你写过千万级数据吗我当场有点答不上来。后来把题目从共享单车数据分析改成基于大数据的共享单车数据分析与可视化加上大数据三个字不光是名字变好听了整个技术栈和研究思路都得跟着换。项目最终完成时我手里握着6个月、1800万条骑行记录用Spark跑清洗和聚合用ECharts做可视化大屏整个链路走下来最大的感受是这个题特别适合想真正入门大数据、又不想只停留在调包阶段的同学。它好就好在数据真实、问题具体、结论能讲出故事而且每一步都有明确的工程交付物不会做着做着就迷失方向。下面我把选题思路、数据清洗、技术选型、分析维度、可视化实现、踩坑记录和答辩准备完整写出来尽量把当时现场怎么想、怎么决定的逻辑也还原出来。你要是也打算做类似的项目可以直接参考我的链路和参数很多地方能帮你少走弯路。1. 为什么是共享单车选题思路与项目目标拆解1.1 一个听得懂、做得动、讲得清的大数据题目选毕设题目的时候我给自己定了三条判断标准数据能不能公开获取、技术栈能不能撑起大数据这三个字、结论有没有业务故事可以讲。共享单车这个方向三条全中。数据获取方面不少城市的开放数据平台都会发布共享单车骑行记录字段包含车辆编号、用户类型、起终点时间、起终点经纬度、骑行距离等。单个月份的数据量就能到几十万甚至上百万条攒上6个月就是千万级这个量级已经足够触发必须用分布式工具的诉求而不会像豆瓣电影评分那样只能在PPT里画饼。技术栈方面共享单车数据天然带有时间和空间两个维度适合做分组聚合、关联分析、地理可视化。更重要的是它能让Spark、Hive、HDFS这些组件在真实数据集上跑起来而不是停留在我学过Hadoop的嘴上阶段。业务故事方面分析结果可以直接落到运营建议上早高峰哪些区域缺车、雨季骑行量下降多少、哪些站点是潮汐黑洞。评委一旦看到这些结论不用你多解释就能理解项目价值还能顺着追问出细节这就给答辩留够了发挥空间。1.2 项目完整链路和每个环节的交付物整个项目我拆成了6个环节数据采集、数据入库、数据清洗、数据建模分析、可视化展示、结论报告。每个环节都有明确的输出物这样才能保证进度可管控也方便在论文里按章节写。数据采集阶段从开放平台按月下载CSV文件数据入库阶段先把CSV导入MySQL的原始表再通过文件方式上传到HDFS挂到Hive外部表上数据清洗阶段用Spark SQL处理缺失值、异常值、格式统一和坐标校验产出清洗后的宽表数据分析阶段基于宽表做多维聚合把结果回写到MySQL可视化阶段后端读取MySQL数据并封装成JSON接口前端用ECharts渲染大屏和静态图表最后把分析结论整理成一份可读性强的数据报告对应论文里的应用章节。我画了一个表来管理每环节的工具和交付物实际推进的时候非常有帮助。环节主要工具输入输出数据采集Python脚本 / 手动下载开放平台接口或CSV文件原始CSV数据入库MySQL、HDFS、Hive原始CSVHive外部表数据清洗Spark SQL原始Hive表清洗后宽表数据分析Spark SQL清洗宽表聚合结果表可视化FastAPI、EChartsMySQL聚合结果大屏/图表页面结论报告Word / Markdown所有分析结果数据报告2. 数据准备比想象中耗时间清洗链路逐步拆解2.1 我遇到的四类脏数据拿到原始数据后第一反应是终于有真数据可以玩了但打开文件之后很快发现事情没那么简单。我从1800万条原始记录里统计出了四类典型脏数据每一类都直接影响后续分析结果的可靠性。第一类是字段缺失。部分记录的经度或纬度为空有些用户类型字段没有取值还有少量记录缺少站点编号。这些都是最常见的坑尤其GPS数据一到隧道、高架桥下面就容易丢信号。第二类是时间异常。有的记录开始时间晚于结束时间有的骑行时长为0还有的时长超过24小时。这类数据对时间维度的分析影响非常大如果不处理画小时趋势图时会出现离谱的尖峰。第三类是距离异常。GPS漂移是共享单车数据的老问题表现在单次骑行距离突然变成几十公里明显超出人类骑行的合理范围。这类记录如果进入距离分布统计会把5-20分钟短途出行这个核心结论完全淹没。第四类是站点名称不一致。同一个站点在记录里一会儿叫人民广场1号门一会儿叫人民广场如果不做归一化处理按站点名聚合时就会把一个站拆成两个空间热力图的准确性大打折扣。2.2 清洗阈值怎么定才不是拍脑袋清洗规则里最容易被质疑的就是阈值。比如超过多少分钟算异常超过多少公里算漂移如果随口说一个数答辩时追问两句就露馅了。我的做法是先用分位数观察数据分布再结合业务常识定阈值最后每条规则都写出依据。骑行时长上限我定为2小时。原因是共享单车的业务场景是最后三公里绝大多数骑行在5到20分钟之间超过2小时的记录很可能是用户忘记还车、车辆被私占或者运维人员调度骑行。如果直接设为30分钟就会把少数真实的长途骑行和郊游骑行砍掉反而引入了偏差。骑行距离上限我结合城市尺度来定。单次骑行超过20公里的记录几乎可以断定是GPS漂移因为正常城市骑行很少有人一口气骑20公里而且共享单车的服务区域也没有那么大。这个阈值比时长阈值更宽松宁可多留一点也不能误伤真实数据。时间逻辑校验必须做的是开始时间早于结束时间、时长必须大于0、日期范围必须在数据采集周期内。这类规则不需要业务判断属于硬性条件直接过滤掉就行。2.3 为什么清洗也得上Spark你可能觉得清洗数据用Pandas就够了为什么要上Spark我当时也这么想过直到我拿着1800万条数据在本地Pandas里做了一次groupby聚合看着内存占用飙到7G笔记本风扇开始起飞才意识到问题没那么简单。Pandas处理1800万条数据的单机过滤完全可行但后续分析要反复做分组聚合、窗口函数、多表关联单机内存会成为瓶颈。而且毕设不是跑一次就完事你每天可能都要根据新想法改分析逻辑每次重跑都是一整套流程。如果用Spark写清洗逻辑后续所有分析作业都在同一个集群环境里运行改一条SQL重新提交依赖不变、环境一致效率反而更高。我最后用Spark SQL写了清洗作业一条语句完成过滤、标准化和派生字段计算。核心逻辑大致长这样INSERT OVERWRITE TABLE cleaned_rental SELECT rental_id, bike_id, user_type, start_time, end_time, start_lng, start_lat, end_lng, end_lat, ROUND(UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time), 0) AS ride_duration, ROUND(2 * 6371 * ASIN(SQRT( POWER(SIN(RADIANS(end_lat - start_lat) / 2), 2) COS(RADIANS(start_lat)) * COS(RADIANS(end_lat)) * POWER(SIN(RADIANS(end_lng - start_lng) / 2), 2) )), 2) AS ride_distance_km FROM raw_rental WHERE start_time IS NOT NULL AND end_time IS NOT NULL AND start_time end_time AND UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time) BETWEEN 60 AND 7200 AND start_lng BETWEEN 73 AND 135 AND start_lat BETWEEN 18 AND 53 AND end_lng BETWEEN 73 AND 135 AND end_lat BETWEEN 18 AND 53;距离字段用的是Haversine公式这是处理经纬度距离的标准做法。把清洗逻辑沉淀成SQL之后后续想调整阈值改一个数字重新提交作业就行不用动Python代码这个体验是Pandas给不了的。3. 技术框架选型用Spark不用MapReduce的现场理由3.1 三个备选方案的对比真正开始写代码之前我在Hadoop MapReduce、Spark、纯Python三个方案之间来回纠结了很久。很多教程一上来就让你搭Hadoop集群然后写MapReduce但我评估之后发现MapReduce的劣势实在太明显。Hadoop MapReduce的问题是开发效率太低。一个简单的分组统计用MapReduce要写Mapper、Reducer、Driver三个类再打jar包提交集群调试一轮下来半天过去了。毕设不是生产环境时间就那么几个月不能把大量时间耗在重复写模板代码上。而且MapReduce跑迭代式计算要把中间结果反复写磁盘性能上也不占优。Spark的优势在于基于内存计算而且Spark SQL直接支持SQL语法写分析逻辑非常顺手。更重要的是Spark生态里DataFrame API和SQL高度统一清洗和分析可以共用一套逻辑调试也方便。Hive负责管理表结构Spark负责计算HDFS负责存储三个组件配合起来正好覆盖大数据处理的标准链路。纯Python方案被我排除的原因是数据量一旦上到千万级单机处理的时间成本和内存成本都不好控制而且在论文里讲大数据技术栈时纯Pandas会让项目底气不足。实际做了对比之后我更确信这个选择是对的。对比项纯Python PandasHadoop MapReduceSpark Hive开发效率高低高运行速度中慢快学习成本低中中高大数据展示效果弱中强迭代分析便利性一般差好3.2 我实际用的集群和作业配置毕设不追求生产级别的高可用所以我没有上多节点高配集群而是用三台云主机组成一个小集群。每台配置是8核CPU、8G内存三台一共24G内存跑1800万条数据的分析按小时计算。Hadoop以YARN模式部署Spark跑在YARN上资源由YARN统一分配。Hive负责建库建表数据存储在HDFS上分区字段设置为月份这样统计月度趋势时可以走分区裁剪速度快不少。核心的Spark参数我调整过好几个版本最后稳定在这组配置上参数名配置值说明spark.executor.memory4g每个Executor分配4G内存spark.executor.cores2每个Executor使用2个CPU核spark.driver.memory2gDriver端内存结果集较大时需要调大spark.sql.shuffle.partitions480控制shuffle后的分区数量影响并发度spark.default.parallelism480默认并行度和分区数保持一致这些参数不是越大越好。Executor内存开太大YARN能分配的Container数量就变少并行度反而下降。分区数太多会产生大量小任务调度开销增加分区数太少又会导致单任务处理数据量偏大内存压力升高。我最后通过Spark UI观察每个Stage的耗时和shuffle数据量调到480分区时基本平稳。3.3 一个实测对比Pandas vs Spark我拿同一份1800万条数据做一个最简单的需求按小时统计订单量。Pandas的写法大概是这样import pandas as pd df pd.read_csv(rental_data.csv, parse_dates[start_time]) result df.groupby(df[start_time].dt.hour).size()这段代码在本地跑内存峰值到了7G左右耗时将近一分半。而用Spark SQL跑同样的逻辑核心SQL就三行SELECT HOUR(start_time) AS hour, COUNT(*) AS cnt FROM cleaned_rental GROUP BY HOUR(start_time);在集群上提交耗时大概20秒而且内存占用稳定。这个对比很能说明问题单机Pandas在千万级数据上已经接近极限而Spark还在舒适区里。当然了单次groupby差距看起来没有多大意义但当分析作业数量从1个增加到20个、30个时总时间的差距就是几个小时和几十分钟的区别了。4. 分析维度怎么定四个方向把共享单车的画像盘活4.1 时间维度早高峰、晚高峰和周末的三种面孔数据分析不要一上来就堆SQL先从业务角度想清楚要回答什么问题。时间维度上我想回答的是共享单车一天里什么时候最忙工作日和周末有没有区别季节变化影响大不大按小时聚合后工作日的数据呈现典型双峰结构早高峰出现在7点到9点晚高峰出现在17点到19点中午和下午相对平稳。休息日则完全不同整体是单峰结构从上午10点开始缓慢爬升下午14点到16点达到峰值之后慢慢回落。这说明共享单车在工作日是典型的通勤工具在休息日则更多承担休闲和购物的短途出行功能。按周聚合的结果显示周一到周五的整体骑行量明显高于周末周一的早高峰比周二到周四更陡。我认为这符合通勤的常识周一大家刚从家里出来公共交通压力大共享单车作为接驳工具自然更抢手。按月聚合的数据则体现出明显的季节特征夏季7月和8月的日均骑行量最高冬季12月和1月最低下降幅度超过40%。这个结论对运营方的意义很大冬天必须缩减投放量否则大量车辆滞留在冷门区域。4.2 空间维度站点热度和潮汐效应的量化办法空间维度上我做了两种分析站点骑行量排行和潮汐效应识别。站点排行用GROUP BY站点ID统计总骑行量取前20名。结果毫无悬念火车站、地铁站、大型商场附近的站点霸榜。但仅仅画一个柱状图还不够还要追问一句这些热门的站点到底是在放车还是在收车这就需要看起终点方向的差异。潮汐效应是共享单车空间分析里最有意思的话题。早高峰大量人从居住区骑车到地铁站或者办公区晚高峰则反向流动导致某些站点在特定时段严重积压或严重缺车。我定义了一个潮汐系数来度量线路的方向不均衡程度潮汐系数 (早高峰A→B次数 - 晚高峰B→A次数) / (早高峰A→B次数 晚高峰B→A次数)这个系数的取值范围是-1到1。越接近1说明早高峰A→B方向的流量远超晚高峰反向流量是强单向潮汐线路越接近-1则正好相反接近0说明两个方向基本均衡。实际计算结果里地铁站到周边写字楼的几条线路潮汐系数都在0.6以上而大学城内部线路的系数接近0说明学生出行方向比较分散没有明显的单向潮汐。这些结论直接变成了可视化大屏上的桑基图一眼就能看清城市通勤的流向结构。4.3 骑行特征与天气的交叉分析骑行时长和距离分布是最直观的用户画像。骑行时长统计结果显示占比最高的是5到15分钟骑20分钟以上的比例快速下降这验证了共享单车是最后三公里接驳工具的业务定位。骑行距离分布也吻合1到3公里区间的订单最多超过5公里的订单占比很低。天气影响分析需要把气象数据关联进来。我从气象开放平台下载了同期每日温度和降雨量数据存成一张天气表然后用日期字段和骑行数据做关联。SELECT w.weather, ROUND(AVG(d.cnt), 0) AS avg_daily_orders FROM daily_orders d JOIN weather w ON d.day w.day GROUP BY w.weather;结果非常直观晴天和无云天气日均骑行量最高小雨天气下降接近30%中雨天气下降超过50%大雨和暴雨天气基本只有晴天的三成。温度方面气温在10到25摄氏度区间骑行量最稳定低于0度或者高于35度时骑行量都明显减少。这个结论可以作为调度系统的前置信号天气预报说第二天有雨运营方应该提前减少投放总量并且把车辆往室内交通枢纽附近调配。4.4 从图表到故事的结论组织分析维度如果只有一个接一个的图表没有主线答辩时很容易讲成一盘散沙。我的办法是把所有结论归纳成三个核心故事第一个故事是共享单车是最后三公里的主力。骑行时长、距离分布都指向同一个事实人们用它解决短途接驳这是产品的核心场景。第二个故事是工作日的潮汐方向反映了城市通勤结构。通过潮汐系数和桑基图可以清晰看到居住区、办公区、地铁站的连接关系这是最漂亮的业务洞察。第三个故事是天气敏感度高调度策略必须前置。下雨天订单量断崖式下降说明共享单车是晴好天气里的弹性需求运营方不能按固定模式投放。这三个故事一条主线串下来从用户行为到空间结构再到运营建议数据和业务就打通了。5. 可视化地图、趋势和指标卡怎么组合成项目门面5.1 图表选型和分析结论的组合表可视化的目标不是把所有图表堆在一起而是让每个图表都回答一个明确的问题。我做了一张图表对照表把分析结论和图表类型一一对应起来这个思路也让前端开发阶段省了不少返工。分析内容图表类型要回答的问题全天订单量趋势折线图什么时候是高峰和低谷工作日与周末对比分组柱状图通勤和休闲怎么区分站点骑行量Top10横向柱状图哪些节点是城市热点站点地理分布地图散点/热力图空间上如何聚集早晚高峰站点流向桑基图潮汐方向往哪走总订单量、活跃用户数、平均时长指标卡项目总体盘子多大后端用FastAPI写了几个只读接口从MySQL读取聚合结果封装成JSON返回给前端。前端不搞复杂工程直接用HTML加原生JavaScript加ECharts这样能减少框架学习成本把精力集中在图表本身。5.2 大屏布局左中右三栏的实操方案可视化大屏是整个项目的门面也是答辩演示最重要的部分。我的布局参考了常见的数据大屏设计按照左时间、中地图、右空间的原则排布。顶部是项目名称和四个核心指标卡总订单量、活跃用户数、平均骑行时长、总骑行距离。这几个数字一出来观众马上就能对项目的体量有概念。左侧从上到下放的是24小时订单趋势折线图和工作日与周末对比柱状图。这是时间维度的核心内容也是数据分析里最容易讲出故事的两个图。中间区域是最大的地图热力图基于高德地图JS API加载城市底图然后叠加一个ECharts散点图层点的大小和颜色深浅映射站点订单量。这里要特别注意坐标系问题后面我会专门说。右侧放的是站点骑行量Top10横向柱状图和早晚高峰站点流向桑基图。右侧是空间维度的补充重点展示潮汐效应。整个大屏用Flex布局宽度自适应。ECharts实例在页面加载完成后统一初始化所有图表的数据来自同一个JSON数据包页面加载后请求一次接口就全部拿回来了。5.3 我在接地图和图表时踩的坑地图容器高度不设置图表初始化出来是0高度页面一片空白。这个问题排查了很久才发现是CSS里忘记设置容器高度ECharts初始化时必须传入一个有明确宽高的DOM容器。坐标系对不上位置偏移几百米。共享单车开放平台给的数据大多采用的是WGS-84标准坐标而国内的地图服务商通常使用加密后的GCJ-02坐标体系。直接用WGS-84坐标在高德地图上打点点位整体偏移明显必须做坐标转换。ECharts实例需要在DOM渲染完成后再初始化。如果页面脚本在body头部执行DOM还没加载完获取到的容器宽度是0所有图表就会渲染失败。我的处理办法是把初始化代码放在window.onload回调里或者把script标签放到body末尾。窗口大小变化后图表变形不自动恢复。这个问题需要监听window.resize事件然后对所有ECharts实例调用resize方法否则大屏拖拽窗口后会留下一片片空白区域。6. 真正难啃的三根骨头数据倾斜、坐标偏移、内存溢出6.1 数据倾斜热门站点把Task直接拖垮项目进行到中期我跑一个按站点加小时的聚合作业发现Spark UI上大部分Task几十秒就完成了但有一个Task跑了将近20分钟整个作业卡在那里不动。这就是典型的数据倾斜。数据倾斜的本质是某个key的数据量远超其他key导致单个Task要处理的数据量特别大而其他Task早就结束整个作业被最慢的那个Task拖着。共享单车数据里火车站附近的站点订单量可能是普通站点的几十倍按站点分组聚合时一定会出现这种问题。我的解决方案是加盐拆分具体做法分两步第一步给热点key加一个随机前缀把它打散让数据分布到多个Task上完成局部聚合第二步将局部聚合结果按key去掉前缀再做全局聚合。这样每个Task处理的数据量都会变得均匀。核心代码逻辑是这样的from pyspark.sql import functions as F # hot_station_ids 是从历史统计里识别出的热点站点 salted df.withColumn( salt, F.when(F.col(start_station_id).isin(hot_station_ids), F.floor(F.rand() * 10)).otherwise(0) ) # 第一次聚合按照加盐后的key局部统计 agg1 salted.groupBy(salt, start_station_id, hour).count() # 第二次聚合去掉盐值汇总全局结果 result agg1.groupBy(start_station_id, hour).agg(F.sum(count).alias(cnt))这个改动之后同样作业的运行时间从20多分钟降到了4分钟左右效果非常明显。实际项目里如果只是少数几个站点是热点也可以用过滤加广播的方式单独处理热点数据但加盐方案通用性更强。6.2 坐标偏移地图点位和实际位置差了五百米做地图可视化时第一版部署后发现点位全部偏移整个热力图的中心位置和真实城市格局对不上。我一开始以为是数据源问题检查了半天才发现是坐标系不匹配。共享单车开放数据大多采用WGS-84标准坐标系这是GPS全球定位系统使用的国际标准。而国内的地图服务商为了符合相关规定对外提供的地图底图通常使用GCJ-02坐标系也叫火星坐标系。把WGS-84坐标直接画在基于GCJ-02的地图上点位会整体偏移几百米。解决方案是写一个坐标转换函数将所有点位从WGS-84转换到GCJ-02后再交给地图渲染。这种转换算法是地理信息领域的公开通用算法网上有现成实现我直接复用了开源Python版本的核心部分import math def wgs84_to_gcj02(lng, lat): a 6378245.0 ee 0.00669342162296594323 d_lat transform_lat(lng - 105.0, lat - 35.0) d_lng transform_lng(lng - 105.0, lat - 35.0) rad_lat lat / 180.0 * math.pi magic math.sin(rad_lat) magic 1 - ee * magic * magic sqrt_magic math.sqrt(magic) d_lat (d_lat * 180.0) / ((a * (1 - ee)) / (magic * sqrt_magic) * math.pi) d_lng (d_lng * 180.0) / (a / sqrt_magic * math.cos(rad_lat) * math.pi) return lng d_lng, lat d_lat实际上我建议直接用现成的坐标转换库比如coord_convert自己手写函数容易出错而且边界情况处理起来很麻烦。转换完之后所有点位的位置就准确了热力图的分布也恢复了正常。6.3 内存溢出三台8G内存的机器差点扛不住集群一共24G内存跑大部分分析作业都还够用但有一次做天气表和订单表关联时出现了Executor OOM作业直接失败。排查过程是这样的先打开Spark UI看失败Stage的详情发现某个Executor的Storage Memory和Shuffle Memory都接近极限。再往下看发现shuffle write的数据量比预期大很多。我当时没给天气表设置广播阈值导致每次shuffle都在传递整张关联表反复传递几百次内存自然被撑爆。天气表本身就是一张非常小的维度表几百行数据完全不应该走shuffle join。只要用Spark的广播机制把这张小表发到每个Executor的内存里让每个Task在本地查表关联就能把shuffle数据量直接降为零。我在代码里加了广播提示和参数配置from pyspark.sql import SparkSession spark SparkSession.builder.appName(weather_analysis).getOrCreate() spark.conf.set(spark.sql.autoBroadcastJoinThreshold, 10485760) # 10MB设置了自动广播阈值之后小表关联的作业不再走shuffleOOM问题彻底消失。同时我也把Executor内存调到了4G分区数保持在480整个作业运行时间和稳定性都改善了不少。排查OOM问题时的思路比具体参数重要先看Spark UI定位内存涨在哪个阶段再看shuffle数据量是不是异常大最后才去调参数。一上来就加内存只会掩盖问题没有解决真正的原因。7. 答辩环节怎么讲清楚这个项目7.1 演示动线先讲数据量再讲大屏最后讲一个结论答辩演示的顺序对印象分影响很大。我当时规划了五分钟的演示动线节奏比技术细节更重要。前30秒快速说明项目规模6个月数据、1800万条骑行记录、三节点集群、Spark处理链路。评委听到这个数据量级马上就知道你确实在做大数据项目而不是拿小Demo糊弄。接下来3分钟演示可视化大屏。先让大屏加载全量数据用光标指到24小时趋势图上指出早高峰和晚高峰两个明显的尖峰然后切到站点Top榜再切到桑基图顺着潮汐方向讲一遍通勤故事。这些图表都是可交互的滚动时会有数据联动演示效果很加分。最后1分半讲一个最有价值的分析结论潮汐效应。把潮汐系数的定义、计算方式、结果和建议一口气讲完评委在这里通常会点头因为他们看到了分析方法不是光画图。7.2 容易被追问的几个问题和回答思路答辩评委问的问题往往不是考察你记住了多少API而是看你是不是真的理解自己的项目。我准备了几个高频问题的回答思路实际答辩时确实被问到了好几个。为什么用Spark而不用MapReduce我的回答是MapReduce开发效率低迭代式计算需要反复读写磁盘而Spark基于内存计算加上Spark SQL可以直接用SQL表达分析逻辑更适合探索式数据分析。毕设项目更看重快速迭代Spark在开发效率和运行性能上全面占优。1800万条数据用Pandas也能处理为什么非要上大数据框架这种问题要老实承认Pandas确实能处理这个量级但处理效率会指数级下降。更关键的是技术选型要面向未来的数据规模如果数据量增长到几亿条Pandas单机方案就完全撑不住了。我的目标是验证一条大数据处理的完整链路而不只是跑通一个数据量级。你的清洗规则依据是什么我的回答是依据业务场景和数据分布双重验证。比如单次骑行时长超过2小时的记录从业务上判断基本不可能是正常骑行再从分位数上看超过这个阈值的记录只占总量很小的比例不影响核心样本。每条规则都有业务和统计两个依据不是拍脑袋。潮汐效应对运营方有什么具体建议这个问题只要能答出来就稳了。我给出的建议是早高峰时段在居住区附近的站点提前多投放车辆晚高峰时段在办公区和地铁站附近加大车辆储备强潮汐线路可以考虑增加调度频次甚至可以设置驻车员在高峰期现场引导。数据量扩到几亿条你的方案需要改哪里我会说当前链路整体可以平移需要改动的主要是资源参数和数据分区策略。Executor内存、并行度需要按数据量重新调整Hive分区策略可能需要从月分区细化到天分区甚至小时分区但架构本身不需要推翻。如果要做实时性更高的应用可以引入Kafka加Spark Streaming把离线链路升级成实时链路。7.3 这类项目后续还能怎么扩展答辩结束后我复盘了一下这个项目虽然拿到了不错的成绩但后续还有很大的扩展空间。如果你有精力可以考虑在现有基础上加入预测模型比如用GBDT或者LSTM预测下一小时的区域需求然后基于预测结果输出调度建议。也可以把离线分析改成实时流处理链路数据源接入Kafka用Spark Streaming实时统计当前各站点的车辆饱和度超过阈值时自动触发调度工单。这些扩展方向在论文里说清楚思路和可行性不一定要实现但能体现你对项目边界有清晰的认知。个人实际做下来最大的体会是毕设项目不一定要多炫酷但一定要把完整链路跑通知道每一层数据是怎么流转的每个组件在中间扮演什么角色。很多时候问题不是出在高深的算法上而是藏在坐标转换这种小细节里。把这些坑一个个填平你对大数据处理的理解就真正落地了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进