我当年在数据开发岗上摸爬滚打这么多年,前后也帮着朋友、学弟学妹们看过不少校招笔试题,其中浩鲸科技这套2020届数据开发类C卷,算是比较有代表性的。为什么这么说?因为这套卷子不是单纯考你背了多少组件参数,而是把“数据开发”这个岗位真正需要的底层能力挨个过了一遍:SQL功底、大数据组件原理、数仓建模思维、甚至还有工程落地时的细节判断。换句话说,它考的不是知识点,而是你有没有“干过活”的思维习惯。
如果你是准备数据开发岗位校招的同学,或者刚转行大数据方向、想系统检验一下自己水平,这篇文章值得认真看完。我会把这套卷子里最核心的考察逻辑拆开揉碎,结合我自己实际写代码、做数仓、调优Hive作业的经验,一条一条告诉你出题人到底想看到什么,以及你该怎么答才能拿高分。文章里不会有那种“背答案式”的套路,只会告诉你底层原理和踩坑经验,顺便帮你把数据开发最核心的知识体系串一遍。
1. 先搞清楚浩鲸科技是一家什么样的公司:业务决定技术栈
1.1 从公司背景看笔试出题方向
浩鲸科技的前身是中兴软创,2020年那会儿已经完成了品牌升级,核心方向是数字化转型服务,客户以通信运营商为主,同时覆盖政务、交通、能源等行业。公司背景直接决定了数据开发岗位的工作内容:运营商级别的海量数据、BSS/OSS系统里的计费详单、用户行为日志、网络信令数据,全都是典型的大数据规模场景。
所以这套C卷的出题方向非常明确:不考花哨的算法,不考深度学习,考的是最贴近生产环境的各项硬功夫。你可以这么理解,浩鲸要招的人,是进去之后能直接上手处理几千张表、每天跑几百个调度任务、能在数据倾斜的时候快速定位问题的那种工程师,而不是只会调包调参的“框架使用者”。
1.2 C卷在整套笔试中的定位
2020届校招笔试采用AB卷或者ABC卷多套并行,主要是为了防止同场考生互相抄袭。C卷作为其中一套,难度和考察范围和另外几套是平行的,但具体题目会有差异。从题型分布来看,数据开发类C卷基本覆盖了四个大方向:SQL编程题、大数据组件原理题、数据仓库设计题、Linux及Shell脚本基础。
这里要提醒一点:很多同学容易忽略Linux和Shell部分,觉得笔试又不考实操,随便准备一下就行。实际上从出题人的角度看,Shell脚本是数据开发最常用的粘合剂,不管是数仓抽数、日志清洗、还是调度任务运维,都离不开Shell。C卷里这部分题目往往不难,但很能拉开差距,因为基础扎不扎实,几道小题目就能看出来。
2. 数据开发岗位笔试的四大核心考察模块
2.1 SQL与关系型数据库功底:所有数据开发的真地基
第一模块一定是SQL,这是毋庸置疑的。但校招笔试里的SQL和你在学校课程里学的SQL完全是两码事。学校教的是增删改查,笔试考的是复杂的多表关联、窗口函数、行列转换、累计统计、分组TopN这些实际业务场景里高频使用的写法。
我见过太多同学,LeetCode刷了一百多道算法题,结果笔试遇到一道需要写开窗函数的SQL就卡住了。原因很简单,平时的练习场景里面几乎没有用到过SQL,更别说在限定时间内手写SQL了。C卷中SQL题目,通常会出现这样几类:排名类问题(经典的分组TopN)、连续类问题(连续登录天数)、占比类问题(各类别的金额占比)、同比环比类问题。每一类都有固定的解题套路,本质上就是窗口函数加子查询的灵活组合。
另外一个容易被忽视的点是:手写SQL的规范性和严谨性。笔试不是机试,不会有编译器告诉你语法错了,所以你必须做到心中有一台“虚拟执行引擎”,在落笔的时候就知道这段SQL的执行计划大概是什么样、会不会有语法歧义、NULL值会不会影响结果。这种能力没有捷径,只能靠平时多写、多读执行计划。
2.2 Java基础与Shell脚本:工具型能力决定你的下限
数据开发岗在大部分公司里,并不要求你像后端开发一样精通Java,但至少得能看懂、能写基础的Java程序。为什么?因为绝大多数大数据框架都是Java生态,MapReduce作业、Spark作业、Flink作业,最终跑的都是JVM进程。笔试里Java题通常不会太深,集中在集合框架、多线程基础、异常处理这些核心知识上。问这些问题不是为了招一个Java开发,而是为了确认你没有“知识盲区”,遇到问题时至少有排查的方向。
相比之下,Shell脚本反而是很多校招生的大坑。C卷里面给了几个常见的场景:写一个脚本循环处理某个目录下的文件、用awk和sed处理文本、用crontab配置定时任务、检查某个进程是否存在并做重启操作。这些题目看起来简单,但非常考验基本功。有过真实操作经验的人,写出来的脚本会考虑到文件不存在、路径带空格、权限不够这些边界情况;而没有实际操作过的同学,写出的脚本往往只能处理“理想状态”,这在出题人眼里一眼就能分辨。
2.3 Hadoop生态组件:从原理到调优的全链路理解
重头戏来了。数据开发笔试必然绕不开Hadoop生态,C卷里关于HDFS、MapReduce、Hive、Spark的题目占了相当大的比重。但这里有个很关键的区分点:校招笔试不考你“用过哪些框架”,而是考你“是否理解框架的底层原理”。比如同样问Hive,常见的问题有这几个层次:第一层是Hive的架构,SQL是怎样转化为MapReduce或Spark作业的;第二层是分区表和分桶表的区别、内部表和外部表的区别;第三层是Hive on MR和Hive on Spark的区别,以及为什么有时候Hive作业跑得特别慢。
对于MapReduce,重点则是整个作业的提交到执行流程:客户端提交作业后,ResourceManager是怎么分配容器的,Map阶段的数据切片是怎么计算的,Shuffle阶段的数据是怎么分区、排序、合并的,Reduce阶段又是怎么拉取数据的。这些细节一个个串起来,其实就是在考察你是否真的理解分布式计算的基本模型。很多同学能说出MapReduce的四个阶段,但说不清每个阶段之间数据的流转格式,这就不算真正理解。
Spark相关的题目也类似。C卷里Spark主要考察RDD的依赖关系、宽窄依赖的区别、Stage的划分依据、Spark Streaming和Structured Streaming的基本原理。如果能顺带说出Spark Shuffle和MapReduce Shuffle的异同点,基本就能拿高分了。实际上面试官和出题人想要的,是那种能清晰表达“数据在框架里是怎么流动的”的人,而不是只会背概念的人。
2.4 数据仓库理论与建模思维:思想层面的分水岭
数据开发和数据仓库之间是分不开的。C卷里数据仓库相关的题目,答得好不好,往往是区分“只是会写SQL的人”和“真正有数仓思维的人”的分水岭。
维度建模是必须掌握的核心理论。事实表和维度表的区别、星型模型和雪花模型的适用场景、缓慢变化维的处理方式,这些都是高频考点。2020年前后,国内互联网大厂已经在大量推行数仓分层体系,ODS、DWD、DWS、ADS这四层分法是主流,笔试中极大概率会出现让你画一个主题的数仓分层设计,或者给定业务场景让你设计事实表和维度表。这部分的考察核心,不是你能不能背出定义,而是你能不能结合具体业务场景说出每张表该存什么、粒度怎么定、主键怎么选。
另外,数据质量相关的题目也值得注意,比如数据重复、数据缺失、数据一致性校验这些。浩鲸做的是运营商系统,每天跑完批处理任务后,第二天早上必须有数据校验报告,一旦发现异常要能回溯问题。所以笔试中出现“怎么保证数据质量”“怎么设计数据稽核方案”这类开放性问题,千万不要只回答一两点,要按事前预防、事中监控、事后补救三个维度来展开,这样逻辑才完整。
3. 典型题型还原与解析:拿到题该怎么一步步拆解
3.1 分组TopN问题:从暴力写法到窗口函数优化
这类题目是SQL笔试的常客。比如:给定一张用户订单表(user_id, order_date, amount),求每个用户下单金额最高的前3笔订单。
第一次接触的同学很可能第一时间想到用自连接或相关子查询,大致逻辑是“找出每笔订单之前有多少笔比它金额大,如果数量小于3,那这笔订单就是Top3”。
SELECT a.user_id, a.order_date, a.amount FROM orders a WHERE ( SELECT COUNT(*) FROM orders b WHERE b.user_id = a.user_id AND b.amount > a.amount ) < 3;这种写法能跑,但性能非常差。如果订单表有几千万行,子查询会对每一行都扫描一次目标表,基本就废了。正确做法是用窗口函数,开一个按用户分区、按金额降序排列的排名窗口,然后过滤排名小于等于3的行。
SELECT user_id, order_date, amount FROM ( SELECT user_id, order_date, amount, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn FROM orders ) t WHERE rn <= 3;这里有两个细节值得注意:一是用ROW_NUMBER()还是DENSE_RANK(),差异在于当金额并列时,两类函数对排名的处理不一样,很多实际业务要求下需要用DENSE_RANK;二是窗口函数中的ORDER BY DESC,如果是金额相同的情况,还需要不要加第二排序字段,取决于业务是否要求“先下单的排在前面”。笔试时写清楚这些边界情况,能充分体现你的SQL功底。
3.2 Hive优化类题目:小文件问题如何处理
小文件问题是Hive生产环境里最经典、也最让人头疼的问题之一。C卷里出了这样一道题:一个Hive表每天产生大量小文件,导致查询和写入性能严重下降,请给出解决方案。
从原理上讲,HDFS上的每个文件都会在NameNode中对应一条元数据记录,文件越多,NameNode内存压力越大。同时,MapReduce作业读取大量小文件时,会产生大量Map任务,每个Map任务的启动和调度都有固定开销,导致整体执行效率极低。
解决思路有几个层次。第一层是控制源头,在写入阶段就尽量避免生成过多文件。比如使用Hive的distribute by配合sort by把相同分桶键的数据分到同一个Reduce任务里。更直接的办法是设置hive.merge.mapredfiles=true和合理的hive.merge.smallfiles.avgsize参数,让Hive在作业结束后自动合并小文件。
第二层是事后治理,针对已经存在的大量小文件,可以写一个临时作业,用INSERT OVERWRITE把这些小文件读出来重新写一遍,在写入时设置合适的Reduce数量。实际生产中我通常的做法是:
SET hive.exec.reducers.max=50; SET mapreduce.job.reduces=50; INSERT OVERWRITE TABLE target_table SELECT * FROM source_table DISTRIBUTE BY RAND();这里用DISTRIBUTE BY RAND()的核心思路是让数据随机分配到50个Reduce任务里,这样输出文件数量不会超过50个。如果不加这个条件,Reduce分配可能不均匀,反而出现新的小文件。这个细节如果不实操过,根本想不到。
作答这类题目的关键是,不要只给出一条方案,要从“预防”和“治理”两个维度结合参数配置和具体SQL来回答,这才是有实际项目经验的人的表现。
3.3 数据仓库设计题:电商订单数仓分层设计
C卷里有一道典型的数仓设计题:给定一个电商平台的订单业务场景,要求设计一套数仓分层方案,并说明每一层的核心表和主要字段。
这道题考查的已经不只是理论知识了,而是你有没有真正理解分层架构在实际业务中为什么要这样设计。我的答题思路一般是这样的:
ODS层(操作数据存储层)直接存放业务库同步过来的原始数据,订单表、订单明细表、商品表等都原样保留,字段不加工,主要是方便日后的数据回溯和核对。这一层必须注意增量还是全量同步的问题,订单表因为有状态变更,通常是增量同步加更新操作,而商品表这种小表基本是全量快照。
DWD层(明细数据层)要做清洗和规范化。比如把订单状态字段从业务里的数字编码统一转换成可读的字符串,把用户手机号脱敏处理,把下单时间和支付时间统一格式化为标准时间戳。这层的数据粒度仍然和ODS保持一致,还是明细级别的,但已经是干净、可用的数据了。
DWS层(汇总数据层)则按照主题进行轻度汇总。比如按用户维度汇总每日下单金额、订单数、支付金额,按商品维度汇总每日销售数量、销售金额,按地区维度汇总每日订单量等。这些汇总结果会被上层直接使用,所以在设计时必须提前想清楚常用查询的条件和维度,才能让汇总表的维度覆盖到位。
ADS层(应用数据层)则完全是为具体报表或应用服务的,说白了就是“你业务方想要什么表,我就在这层给你拼什么表”。比如销售大屏要展示今日全平台GMV、各品类销售排行、各地区销售地图,ADS层就单独建一张报表表,把DWS层的数据再加工成最终展示结构。
回答这类题目时,我建议你在纸上把每一层的表和核心字段都列清楚,并顺带说明为什么要分这么多层。理由很直接:解耦。从ODS到DWS,每一层都承担着明确的职责,业务方如果临时要一个新的统计口径,通常不需要回溯到ODS原始日志,而是基于DWD或者DWS就能完成加工,这样既节省了开发时间,也降低了出错后排查问题的成本。
3.4 MapReduce原理题:WordCount之外的理解深度
MapReduce原理题,最怕的就是只会背WordCount流程。C卷里有一道题问的是:一个MapReduce作业从提交到结束,任务调度和数据流转是怎么完成的。
我建议回答时一定要按时间线把全流程串起来:客户端向ResourceManager提交作业后,RM会先根据作业的输入路径和输入格式计算出分片(split)信息,每个分片会对应生成一个Map任务;随后RM在集群中分配容器,并在NodeManager上启动ApplicationMaster;ApplicationMaster是作业的“管家”,它负责向RM申请后续Map和Reduce任务所需的资源;Map任务读取分片数据,经过map函数处理后,将输出结果写入缓冲区,待缓冲区达到阈值后溢写(spill)到本地磁盘,这个过程里要做分区、排序和合并;Map任务全部完成后,Reduce任务开始从各个Map任务所在节点拉取属于自己的那部分分区数据,这一步就是Shuffle中的Fetch阶段;Reduce端还会做一次归并排序,然后交给reduce函数处理,最终结果写到HDFS上。
如果到这里就说完,分数不会太低,但想拿高分,还得补充两个细节:一是数据切片大小默认是块大小,也就是128MB,如果输入文件很小,会启动大量Map任务,这是小文件问题能拖垮整个集群的根源;二是Reduce任务默认数量是1,如果你想让输出结果有多个文件,就需要手动设置mapreduce.job.reduces。这两个点能体现你对作业执行过程的理解不只停留在概念层面。
4. 从笔试看日常准备:怎么学才算学到点子上
4.1 刷题之外的原理闭环:把“知道”变成“理解”
数据开发笔试的准备,最忌讳的就是零散刷题,东看一眼Hive优化,西看一眼Spark原理,看完就忘,下一套题照样不会。我自己的经验是,知识点是要形成“闭环”的。什么意思?你学到一个新概念,比如Hive的谓词下推,不要停留在“知道有这么个参数”层面,要主动追问几个问题:它下推的逻辑是什么?在Map阶段还是Reduce阶段执行?在什么情况下不会下推?然后动手去环境里造数据验证。这个过程走完了,这个知识点才真正变成你的。
笔试里很多题目看着是考原理,实际考的是你能否将原理用于排查问题。比如为什么一个简单的关联查询跑了几个小时?如果你知道MapReduce的执行计划,知道关联操作里大表驱动小表时的MapJoin优化,就能说出可能是其中一个表太大导致Reduce端数据倾斜。这种“原理到问题”的映射能力,才是备考中最重要、也最花时间的能力。
4.2 项目经历怎么讲才有说服力
除笔试之外,后续的面试一定会问项目经历。很多同学写项目经历就是罗列技术名词:使用了Hive,使用了Spark,使用了Kafka。这种写法一点说服力都没有。要让项目经历有说服力,必须包含三样东西:数据量级、遇到的问题、以及你怎么解决的。
同样是做用户行为日志分析,你可以说“日处理日志约1亿条,使用Flume采集到Kafka,再用Spark Streaming做实时清洗,写入ClickHouse。遇到数据重复消费的问题,通过在Kafka消费者中记录已处理的offset并结合去重逻辑解决。”这样讲出来,面试官立刻就能判断你确实解决了实际问题,而不是照着教程搭了个Demo环境。C卷笔试里很多开放性问题,其实也是在模拟这种“真实场景遇到问题”的作答方式。
4.3 笔试作答的时间分配策略
数据开发类笔试一般时长在90分钟到120分钟之间,题目量和难度都不小。我见过很多同学在后面的大题上花太久,导致前面的基础题没时间做,非常可惜。
我的建议是:先快速通读全卷,用2到3分钟判断每题难度和分值。通常SQL编程题是必须拿下的,如果你在10分钟内没思路,先做个标记跳过去;组件原理题如果是选择题或简答题,尽量一遍过,不要反复纠结;Shell脚本题和数仓设计题分值高、但理解门槛不高,适合放在最后保障完成度。等基础题全部完成,再回头攻克前面的难题,这样即使最后大题没做完,卷面的完成度和得分率也会高很多。
5. 笔试中那些防不胜防的“坑”
5.1 审题不清比不会做更可惜
校招笔试里,大量丢分不是因为题目难,而是因为审题不清。数据开发题目通常会在题干里埋很多限定条件,比如“统计每个用户最近7天的消费总额”,你以为这是简单的分组求和,但如果表里时间字段是字符串类型,你就需要先做格式转换;如果一天有多个订单,你需要先按天聚合再去计算7天窗口。这类题目最容易出错的地方就是把日期格式化处理漏了,直接导致结果偏差。
另一个高频审题问题是“要不要去重”。统计用户数时用COUNT(USER_ID)和COUNT(DISTINCT USER_ID)结果差很多,必须要看清题目问的是“总用户数”还是“活跃用户数”,以及订单表里一个用户是否可能出现多次。
5.2 手写SQL的规范和边界条件
手写SQL时,不少同学会犯一些很低级但致命的错误:字段名写错、表别名没加、子查询没起别名、分组字段不完整。笔试没有编译器报错,所以你必须养成“落笔就是正确代码”的习惯。
尤其要注意的是聚合函数和NULL值的处理。COUNT(*)和COUNT(字段名)在存在NULL值的时候结果不同,SUM遇到全NULL会有问题,GROUP BY后的HAVING条件要写对位置。还有窗口函数的写法,PARTITION BY和ORDER BY的顺序以及ROWS BETWEEN的边界定义,都是非常容易写错的地方。
5.3 原理题答不到点子上时怎么补救
如果遇到一道原理题确实一知半解,不要直接放弃或者写一堆无关内容。你可以尝试从已知的知识点推导出合理的结论。比如让你解释Spark作业为什么比MapReduce快,即使你不记得所有细节,也可以从“Spark基于内存计算,中间结果不落盘”“Spark使用DAG调度,能够减少不必要的Shuffle”“Spark的Task启动开销比MapReduce小”等几个方向展开,至少能拿一半以上的分数。
我在企业里做数据开发用的核心工具就是Hive、Spark、Flink这一套,笔试后的第三年我又回头看过这套题。说句实话,这些题考察的逻辑至今没有过时。现在很多公司校招数据开发笔试,依然在用类似的框架:SQL或者Python选一个作为主编程语言、大数据组件原理、数据仓库设计思维、项目实战分析。如果你能把这套C卷涉及的知识点彻底吃透,后面再遇到别的公司笔试也不会慌,因为底层的知识体系是一样的,变的无非是业务包装,换汤不换药。