摩拜2018数据工程师笔试题解析:从SQL到Spark的考察逻辑
2026/9/1 14:30:54 网站建设 项目流程

第一次看到“摩拜2018校招数据工程师笔试卷”这个题目,是在一个收藏夹里翻到的。那会儿共享单车正打得火热,摩拜和ofo满街都是,传感器、智能锁、海量骑行轨迹,这些都是实打实的数据资产。作为经历过那个阶段的数据工程师,我可以负责任地说一句:这张卷子的含金量,不在于它考了多少个技术点,而在于它把“数据工程师”和“普通后端开发”彻底区分开了。今天我就以亲历者的视角,拆解这份试卷背后真正想考察的东西,以及今天再看它,哪些题依然能打,哪些思路已经升级了。

如果你正在准备数据工程师的校招,或者刚入行想搞明白这个岗位到底要会什么,这篇文章值得你花十分钟读完。我尽量不讲空话,把当年笔试的考察逻辑、典型题目类型、以及对应的复习路径,一次性给你理顺。

1. 摩拜这场笔试的底色:业务驱动型数据团队到底在招什么人

1.1 为什么一张2018年的试卷,今天还有参考价值

很多人看到“2018年校招”就下意识觉得过时了。但数据工程师这个岗位有个特点:核心考察的底层能力,五年甚至十年都不会变。2018年那会儿,Spark已经普及,Flink刚开始火,Hive依然是离线数仓的主力。摩拜的笔试不会直接考你Flink的Watermark机制,因为它招的是校招生,不是有三年经验的实时计算专家。它真正想看的是:你拿到一批杂乱的数据,有没有能力把它变成可分析的形态;你面对一个业务问题,有没有能力把它拆成可执行的计算逻辑。

这个底层能力,放到2025年的今天依然成立。变化的是什么?是工具链的迭代。比如当年的Hive SQL题目,放到今天可能会变成Spark SQL或者Flink SQL;当年的MapReduce思想题,今天可能变成对Pandas groupby的性能优化。所以这张试卷的参考价值不在“原题复现”,而在“考察逻辑复现”。

1.2 摩拜的数据工程师和互联网大厂的数据工程师,差在哪

我先说一个容易踩的误区:摩拜不是一家纯粹的互联网公司。它是一家有海量IoT设备的物理世界数据公司。每辆车上有智能锁,锁里有GPS模块和通信模块,用户扫码开锁、骑行、关锁,每一步都会产生一条记录。

这意味着它的数据工程师要处理的问题,跟电商、社交类公司有明显差异:

  • 数据采集链路很长:从设备端到服务端,中间有网络延迟、断线重连、数据补传,原始数据里充满脏数据和时间乱序。
  • 空间数据是核心:每一条骑行记录都关联经纬度、轨迹点,涉及地理计算,不是简单数个数就行。
  • 实时性要求高:车辆调度、骑行安全提醒、故障判断都需要实时或准实时的数据处理能力。

所以笔试题目会刻意往这些业务特点上靠。如果你用纯互联网思维去答,很容易答偏。比如问“如何统计某区域骑行量”,你要想到的不只是SQL怎么写,还包括这个区域的边界怎么定义(行政区域?地理围栏?)、数据怎么清洗(漂移点怎么处理)、以及实时性要求(是T+1报表还是分钟级看板)。

1.3 校招笔试的真正目的:筛掉只会背题的人

以我面试校招生的经验来说,笔试的目的从来不是筛出“最牛”的人,而是筛掉“不合格”的人。摩拜的笔试题目设计得很典型:基础题占六成,进阶题占三成,拔高题占一成。基础题考的是你大学四年有没有认真学数据结构和数据库;进阶题考的是你有没有真实的数据处理经验;拔高题考的是你有没有主动思考过数据背后的业务价值。

2. 从Hive到Spark:大数据组件选型题背后的考察意图

2.1 “请简述Hadoop生态各组件的用途”这类送分题,为什么也会有人翻车

这种题目看起来简单,但恰恰是区分“背过八股”和“真用过”的分水岭。简单版答案谁都会背:HDFS是分布式文件系统、MapReduce是分布式计算框架、Hive是数据仓库工具。但如果面试官追问一句“HDFS适合存什么数据、HBase适合存什么数据、Kafka适合存什么数据”,很多人就开始含糊了。

我当时梳理了一个比较清楚的思路,分享给你们:

组件典型使用场景不适合的场景一句话理解
HDFS海量大文件批量存储,离线分析随机读写、实时查询一个巨大的文件柜,适合归档和批量读取
HBase海量数据的随机实时读写复杂聚合分析一个巨大的键值表,适合按rowkey快速查
Kafaka数据缓冲、削峰填谷、解耦长周期数据存储一个高速传送带,数据流动但不常住
Hive离线ETL、统计分析毫秒级交互查询把SQL翻译成MapReduce的工具
Spark内存计算、迭代计算、机器学习超大规模离线ETL不如Hive稳比MapReduce快很多的计算框架

这道题的答题逻辑不在背表格,而在理解数据生命周期:数据先经过Kafka收集,落到HDFS做离线分析,或者通过Spark做实时/准实时处理,然后把热数据放在HBase供业务查询。这个链路捋顺了,组件选型题基本不会失分。

2.2 笔试里没明说、但真正想考的:分区、分桶、小文件问题

不夸张地说,小文件问题是很多数据工程师入职后踩得最多的坑。笔试题如果只出“简述Hive分区和分桶的区别”,那属于送分题。我见过摩拜笔试卷里有一种更高级的问法,大意是:“某张订单表按天分区,但每天的数据量只有几MB,长期运行后查询越来越慢,你如何优化?”

这里头藏着三层考察点:第一,你知不知道小文件太多会导致NameNode内存压力大、Map任务数量爆炸;第二,你知不知道解决办法(合并小文件、设置动态分区参数、用Spark repartition);第三,你有没有能力把方案落地成一两条具体的Hive/Spark配置。

我建议大家都背一下这几个常用调优参数,笔试和面试都用得上:

-- Hive中合并小文件 SET hive.merge.mapfiles = true; -- 合并Map端输出的小文件 SET hive.merge.size.per.task = 256000000; -- 合并后每个文件的目标大小(256MB) SET hive.merge.smallfiles.avgsize = 16000000; -- 如果平均大小低于16MB,触发合并

在Spark里则可以用coalesce或repartition来控制输出文件个数,比如df.coalesce(10).write.mode("overwrite").parquet("/path")。笔试里能写出这一层,就已经超过八成候选人了。

2.3 从2018到2025:组件题目的演进方向

摩拜2018年的笔试卷里,Spark大概率只会出一道“和MapReduce的区别”这种基础题。放到今天,面试官更可能会问“Flink和Spark Streaming的区别”“Paimon和Iceberg选哪个”“为什么湖仓一体这么火”。工具永远在变,但题目背后的逻辑不变:数据结构、数据生命周期、数据处理范式。所以我给各位的建议是,组件题不要死记硬背,而是抓住“数据从哪来、存哪去、怎么算、怎么查”这条主线。

3. 笔试中最容易拉开差距的SQL题:从“会写”到“会优化”

3.1 摩拜考题里那几道高频SQL,核心就这几种模式

SQL是数据工程师笔试的必考项,也是性价比最高的复习项。我翻了不少校招笔试题,发现来来回回就那几种套路。你要是能把下面这六种模式练到肌肉记忆,SQL题基本稳了:

  1. 分组聚合:GROUP BY + COUNT/SUM/AVG,注意HAVINGWHERE的区别。
  2. 去重统计:COUNT(DISTINCT user_id),注意大数据量下的性能隐患。
  3. 窗口函数:ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY start_time),用于取每组TopN。
  4. 行转列/列转行:SUM(CASE WHEN ...) / UNION ALL,或者用LATERAL VIEW EXPLODE
  5. 自连接:用于找连续行为、比较同一实体不同记录。
  6. 留存计算:用DATE_SUBDATE_ADD做日期偏移,再按活跃期分组去重。

我来举个典型的“用户首单时间”问题,这个在共享单车场景里就是“每个用户的第一次骑行时间”。大部分人第一反应是用GROUP BY user_id + MIN(start_time),这没问题。但如果要同时取出首单对应的那条记录的完整字段,就必须用窗口函数了:

SELECT user_id, start_time, end_time, distance FROM ( SELECT user_id, start_time, end_time, distance, ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY start_time ASC) AS rn FROM ride_records ) t WHERE rn = 1;

你发现没有,这两段代码的差别不只是语法上多了个子查询,而是思维模式的差别。前者是“聚合思维”,后者是“排序取数思维”。数据工程师要的恰恰是后者——因为你日常工作中遇到最多的问题,不是“算个总数”,而是“把每组里满足条件的记录拎出来”。窗口函数就是干这个的。多练ROW_NUMBERLAGLEADSUM() OVER(ORDER BY ...)这几兄弟,SQL水平会有明显提升。

3.2 那些笔试里不会告诉你的SQL性能细节

有些候选人SQL写得很顺,但一追问性能就露馅。比如说“如何统计每天骑行用户数”,如果表里数据量是几十亿行,直接SELECT day, COUNT(DISTINCT user_id) FROM ride_records GROUP BY day,跑一轮可能要几个小时。这就是典型的“算得出来,但不合格”。

合格的数据工程师应该想到:

  • 如果允许一定误差,用APPROX_COUNT_DISTINCT或HyperLogLog算法;
  • 如果每天用户量很大但重复率也高,先GROUP BY day, user_id去重再统计,会比直接COUNT(DISTINCT)更省资源;
  • 如果只需要报表数据,提前把去重后的结果物化成中间表,避免每次全量扫描。

我会建议大家在练习SQL时,刻意给自己设一个“数据量是十亿行”的假设,然后思考你的写法是否还成立。这个习惯养成了,笔试里的SQL优化题根本不会难倒你。

3.3 笔试题里的SQL坑位:一个具体的踩坑复盘

回到摩拜这份卷子。我印象很深的一道题:“统计每个城市注册用户中,在注册后7天内至少完成1次骑行的用户数。”不少考生直接就JOIN注册表和骑行表,然后GROUP BY city。这确实能得到一个数,但不一定对。

坑在哪里?在“注册后7天内”这个时间条件。如果你在WHERE里写a.reg_date + 7 >= b.ride_date,但注册表里一个用户在多个城市有注册记录(比如手机号换绑、或者一个小号),或者一个用户在7天内骑了多辆车,就会产生多条记录——最终导致用户被重复计数。正确做法是先DISTINCT用户,再统计:

SELECT city, COUNT(DISTINCT user_id) AS active_users FROM ( SELECT a.user_id, a.city, b.ride_date FROM users a LEFT JOIN ride_records b ON a.user_id = b.user_id AND b.ride_date BETWEEN a.reg_date AND DATE_ADD(a.reg_date, 7) WHERE b.user_id IS NOT NULL ) t GROUP BY city;

这个例子的价值不在SQL本身,而在它提醒你:笔试题里的业务条件,每一句都要拆开想清楚。多一条JOIN,就多一层去重的风险;多一个时间窗口,就多一处边界要考虑。严谨性,就是数据工程师的核心竞争力。

4. 数据分析与统计题:当业务方甩给你“骑行时长下降了5%”

4.1 笔试里的统计题,考的不是算术,是业务决策

摩拜这类公司的数据分析题,通常不会只考你“会不会算均值、中位数”,而是考你“拿到一个业务波动,怎么定位原因”。我在实际工作中经常遇到类似的问题:“为什么这周骑行时长下降了5%?”第一次面对这种问题的人,第一反应往往是“数据出bug了吧”,或者“运营没做活动”。这都很正常,但这不是数据工程师该给的答案。

一份合格的业务异动分析答卷,应该包含这样几个步骤:

  • 先验证数据口径:骑行时长的统计口径有没有变化?是不是有新的版本上线,把时长字段截断了?
  • 再拆维度看:是全天都在下降,还是早晚高峰下降?是全国下降,还是某些城市下降?是新用户下降还是老用户下降?
  • 然后结合外部因素:是不是下雨了?是不是竞争对手在搞免费骑行?是不是考试周,学生用户集体不骑车了?
  • 最后给出建议:如果是天气影响,那属于正常波动;如果只有某些城市下降,要去查是不是那些城市的车辆运维出了问题。

笔试里如果能写出这种结构化思路,即使没有精确数字,面试官也会觉得你是“有数据 sense 的人”。

4.2 一道典型的“异常检测”题:不会算法也能拿分

我记得2018年摩拜笔试的题库里有这么一类题:“某区域某天的订单量从平时1000单暴涨到5000单,你怎么判断这是正常活动还是数据异常?”大部分人的第一反应都是“用3σ原则”或者“用IQR”。但笔试的坑在于:你没有历史建模的条件,只能用最朴素的方法先做判断。

我会给出的答题框架是:

  • 先按小时粒度查看单量分布,如果只是某个小时暴涨,其他小时正常,更可能是数据重复上报;如果全天都涨,才可能是真实活动。
  • 再对比同一时间段的附近区域有没有同涨,如果只有这一个区域涨,可能是新开了商圈或举办了活动。
  • 最后还可以看用户新增比例,如果新增用户占比特别高,可能是刷单或外部导流。

这个思路的核心是“多维度交叉验证”,而不是一上来就套模型。校招笔试不可能要求你写一个完整的异常检测算法,但一定要求你有这个分析方向感。这一点,哪怕你没有系统学过机器学习,也能答得很好。

4.3 留存、漏斗、分组对比:共享单车场景下的统计应用题

共享单车的统计题,和电商不太一样。电商的“留存”通常看次日、7日、30日,但共享单车是线下场景,用户往往只在上下班、周末骑行,所以“次日留存”可能很低,但这不代表产品不好。一道好的笔试题会把这个现实困境摆在你面前:某城市月活跃用户数在增加,但月人均骑行次数下降了,你怎么看?

这类题的关键是“分层”。月人均骑行次数下降,可能的原因太多了:新增用户多但使用频次低,拉低了平均值;老用户流失严重,剩下的低频用户拉低了平均值;短途骑行需求被其他出行方式替代。每一步都需要数据和业务逻辑互相印证。笔试答题时不要慌,先用“用户分层”搭框架,再把可能的原因填进去,最后指出“下一步我建议用XX数据验证”。这套打法比单纯算一个数高一个维度。

5. 代码题与算法题:数据工程师的“算法”到底考什么

5.1 不会让你白板写红黑树,但Python/Pandas操作躲不掉

现在很多准备校招的同学,一说算法题就刷LeetCode,刷得很辛苦。但对数据工程师这个岗位来说,纯算法题的比重没那么高,大部分公司的笔试会改成代码实操题,或者干脆让你在线上环境跑一段数据处理逻辑。摩拜也不例外。

比如有一道很典型的题:“一张骑行订单表,gps_start字段格式是'lat,lng',请拆分出经纬度,并计算每条订单的起终点直线距离。”这题用Pandas解就很方便:

import pandas as pd import numpy as np # 示例数据 df = pd.DataFrame({ "order_id": [1, 2], "gps_start": ["39.9042,116.4074", "31.2304,121.4737"], "gps_end": ["39.9142,116.4174", "31.2404,121.4837"] }) # 拆分经纬度 df["start_lat"] = df["gps_start"].str.split(",").str[0].astype(float) df["start_lng"] = df["gps_start"].str.split(",").str[1].astype(float) df["end_lat"] = df["gps_end"].str.split(",").str[0].astype(float) df["end_lng"] = df["gps_end"].str.split(",").str[1].astype(float) # 用Haversine公式计算球面距离 def haversine(lat1, lng1, lat2, lng2): R = 6371.0 # 地球半径,单位km phi1, phi2 = np.radians(lat1), np.radians(lat2) d_phi = np.radians(lat2 - lat1) d_lambda = np.radians(lng2 - lng1) a = np.sin(d_phi / 2)**2 + np.cos(phi1) * np.cos(phi2) * np.sin(d_lambda / 2)**2 return 2 * R * np.arcsin(np.sqrt(a)) df["distance_km"] = haversine(df["start_lat"], df["start_lng"], df["end_lat"], df["end_lng"]) print(df[["order_id", "distance_km"]])

这里有一个隐形的考点:如果你直接用经纬度的欧氏距离当物理距离,那就踩坑了。纬度1度约为111公里,但经度1度在赤道附近也是111公里,在北纬40度则只有85公里左右。所以只能用球面距离,或者至少对每个城市的经度做系数校正。这个细节,就是数据工程师和普通脚本开发的分水岭。

5.2 考逻辑不考模板:MapReduce思想的变体考察

回到2018年的语境,Spark已经很流行,但很多高校的课程还在教MapReduce。摩拜笔试如果考“给定一个用户骑行记录文件,统计每个用户的总骑行距离”,它不会让你写完整的MapReduce代码,而是让你说出思路:Map阶段把记录拆成user_id -> distance的键值对;Shuffle阶段按user_id分组;Reduce阶段累加距离,输出结果。

用今天的语言翻译一下就是:df.groupby("user_id")["distance"].sum()。很多候选人觉得这种题太简单,但它的价值在于考察“分布式计算思维”有没有建立起来。你自己写代码时,可能会下意识写一个双重循环;但如果你习惯了MapReduce思维,你会先想“能不能拆成Map和Reduce两步”。这种思维模式的转变,是校招笔试最想看到的。

5.3 面对“大规模数据”情境题,别急着写代码

拔高题往往长这样:“一份订单数据有100亿条记录,按天分表,现在要统计每个用户过去7天累计骑行时长Top100的用户列表,你会怎么做?”如果直接回答SQL JOIN,说明你还没建立起数据量级的概念。正确的拆解路径是:

  • 先按天过滤,只读取最近7天的分区,避免全表扫描;
  • 再用GROUP BY user_id, SUM(duration)聚合;
  • 最后用窗口函数ROW_NUMBER()取出每个用户的总时长Top100,或者如果只需要Top100用户,就全局排序取前100。
  • 如果数据量确实大,可以考虑用approxTopK算法,或者先用filter把活跃用户圈定出来再排序。

这道题从“可行性”到“性能”到“准确性”,每一步都在考察候选人的取舍能力。笔试里不会被要求写出完整代码,但思路必须清晰。

6. 复习清单与避坑建议:按这份经验去准备校招笔试

6.1 先把基础砸实,再谈技巧

很多同学的备考顺序是反的:先刷了大量LeetCode,然后发现SQL不熟,又临时抱佛脚看窗口函数。我的建议是,花一周时间把数据库基础、Hadoop生态核心组件、Python数据处理三板斧(Pandas、NumPy、PySpark)过一遍,再做题。尤其是Pandas,笔试中如果允许用Python,Pandas能帮你省下大量时间,比手写Python原生循环快太多。

6.2 针对摩拜这类“物理世界数据”公司的专门准备

如果你明确知道自己要去摩拜、滴滴、哈啰这类公司,建议额外准备几个方向:地图坐标与距离计算(GCJ-02坐标、火星坐标系)、设备数据上报的乱序和去重、空间聚类在城市调度中的应用。这些内容在通用面试题里不太会碰到,但恰恰是这类公司最看重的差异化能力。

6.3 笔试答题的时间和取舍策略

我自己当年做题有个策略,分享给你们:拿到卷子先花2分钟把所有题目扫一遍,把“会做但需要时间”的题标记出来,先做“会做且快”的题,最后留时间给“有点思路但不确定”的题。千万不要在一道SQL优化题上死磕30分钟,结果后面一道Python数据处理大题没时间写。数据工程师笔试写不完很常见,但写不完“能拿分的题”就没必要了。

6.4 笔试之后的复盘才是涨分关键

最后一次提醒:笔试结束后,无论结果如何,一定要做复盘。把你卡住的知识点记下来,看看是SQL窗口函数不熟、还是Pandas的merge方向搞反、还是对HDFS存储原理理解不透。校招笔试不是一个“考完就结束”的事情,它是你查漏补缺的最佳指南针。这些曾经答不上的题,很可能就是你入职后第一周会碰到的真实需求。

写到这里,我突然想起当年一起准备校招的朋友说过一句话:“数据工程师这个岗位,看起来是跟数据打交道,本质上是跟业务逻辑和工程效率打交道。”一张试卷刷完,不是终点。真正重要的,是你在准备过程中有没有建立起一套面对海量数据的思考方式。希望你也能从这些题目里,看到这条路的地图。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询