尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

京东数据开发笔试题解析:SQL、数仓与分布式核心考点

京东数据开发笔试题解析:SQL、数仓与分布式核心考点 2018年京东秋招的数据开发笔试题我到现在还留着电子版。那年我也投了虽然没走到最后但那份卷子前前后后刷了三遍后来自己也做了几年大数据开发再去回看才发现那些考点背后其实就对应着一个数据开发工程师日常要干的活。很多朋友问我现在准备数据开发面试该看什么我的回答一直是先把老牌大厂的历年校招笔试题吃透京东这卷子就很有代表性SQL、数仓、Hadoop生态、算法都有覆盖难度适中非常适合用来查漏补缺。这篇文章我会从题目考什么、怎么解、有哪些隐藏坑这几个角度去拆顺便把数据开发笔试里最高频的题型思路讲透。不管你是准备校招还是想转岗数据开发都可以拿这份内容当复习提纲。我尽量少说废话直接给你能用的东西。1. 笔试题背后的能力模型数据开发工程师到底考什么1.1 为什么一张2018年的笔试题还值得翻出来看很多同学有个误区觉得技术迭代快2018年的题早就过时了。但数据开发岗位本身不是追新技术的岗位它的核心是数据仓库设计、离线计算、实时计算、数据质量保障这些东西底层逻辑非常稳定。哪怕今天我们已经大量使用Spark、Flink但Hive SQL仍然是离线数仓的主干MapReduce思想还在数据倾斜问题也还在。2018年的笔试题考的是这些底层能力现在依然在考而且大概率还会继续考。另外一个原因是大厂笔试的出题风格一般比较克制不会出偏题怪题而是考“能不能干活”的基本功。京东这套题就是典型SQL占大头附带了数仓模型、分布式计算原理和少量算法编程。这刚好映射了一个数据开发工程师的真实工作场景——你每天写的ETL就是SQL你设计的表结构就是数仓建模你优化的任务就是在跟分布式系统打交道。笔试不是在考你记忆而是在模拟你能不能接手真实任务。1.2 数据开发笔试的范围与权重根据我看到的公开回忆版和后续和几个参加过那场笔试的同学对答案这套题的题型分布大概是下面这个样子考察方向常见题型大概占比考核目标SQL/Hive窗口函数、多表关联、连续问题、行列转换35%-40%日常取数与ETL能力数据仓库理论分层设计、事实表维度表、拉链表15%-20%建模能力与业务理解分布式计算原理MapReduce流程、Shuffle、HDFS读写10%-15%对底层架构的理解算法/数据结构TopK、排序、哈希、手写代码15%-20%代码基本功与大数据思维Java/Python基础集合、IO、线程或语法题5%-10%工程落地能力这个权重分布不只在京东在多数互联网大厂的数据开发笔试题里基本都成立。如果你现在复习时间不多按这个顺序分配精力是最稳的。SQL绝对是性价比最高的部分练好了笔试能过工作也能直接用上。1.3 数据开发岗位和其他数据岗的考核差异我见过不少同学把数据分析师和数据开发工程师的笔试混着准备结果两边都没抓住。数据分析岗更侧重Excel、Python分析库、AB实验、业务指标设计对SQL的考察也往往是取数逻辑而数据开发岗更侧重性能优化、数据准确性、调度依赖、分布式原理。同样是写一段SQL数据分析师只要查出对的结果就行数据开发还要考虑数据量大了怎么不跑挂、怎么减少扫描量、怎么避免数据倾斜。所以在笔试准备上你不能只会“查数据”还要知道“怎么存数据”、“怎么高效算数据”。比如同一道分组TopN的题数据开发岗往往还会追问一句如果这个表有十亿行你的SQL会不会OOM这时候你光写出row_number()是不够的还得想分区裁剪、谓词下推、Map端聚合这些事。这也是大厂笔试题喜欢设的陷阱——表面考SQL实际上考工程思维。2. 高频考点拆解SQL与Hive的重点题型2.1 窗口函数从“分组求TopN”说起分组求TopN是所有数据开发笔试里最经典的一道题没有之一。题目通常是有一个员工表部门、姓名、薪资求每个部门薪资最高的前三个人。正解是使用窗口函数select 部门, 姓名, 薪资 from ( select 部门, 姓名, 薪资, row_number() over(partition by 部门 order by 薪资 desc) as rn from 员工表 ) t where rn 3;这里容易踩的坑有两个。第一个是row_number()、rank()、dense_rank()的区别没搞清楚如果题目要求“薪资相同并列排名且占用后续名次”就得用rank()如果要求并列但不超过TopN就用dense_rank()。很多人背了函数名却不知道选用场景笔试时被问“TopN允许并列怎么办”直接懵掉。第二个坑是把窗口函数放在where里过滤比如写成where row_number() over(...) 3这在SQL语法里是不允许的窗口函数只能在select或order by子句中使用。老实说这个错误我在实际工作里见过不止一次因为很多人在IDE里写SQL会顺手想这么做。笔试时一道大题里出现这种低级语法错误印象分会很惨。除了TopN窗口函数还需要掌握累计求和sum() over(order by 日期)、移动平均、分组占比avg() over(partition by ...)这类场景。这些都是离线数仓开发里非常常用的工具面试官很容易在笔试题里变着法考。2.2 连续性问题连续登录N天怎么算另一道高频题是“求连续登录N天以上的用户”。比如给定用户登录日期表uid, login_date让你求连续3天登录的用户。核心思路很经典用登录日期减去row_number()的序号如果连续差值会相同再按用户和差值分组计数。select uid from ( select uid, login_date, date_sub(login_date, row_number() over(partition by uid order by login_date)) as diff from login_log where login_date between 2018-01-01 and 2018-01-31 ) t group by uid, diff having count(*) 3;这道题看起来不难但有个细节特别容易翻车用户同一天可能有多条登录记录如果不去重row_number()算出来会错。正确做法是先做select distinct uid, login_date再去算连续。我见过不止一个同学在这上面丢掉全分。还有更进阶的变体比如“求每个用户连续登录的最大天数”。思路是在上面基础上算出每个uid的连续分组diff然后group by uid求max(cnt)。这种连续问题的本质是“构建与日期无关的分组标识”理解这个原理之后不管题目怎么换你都能把业务场景抽象成同一套解法。2.3 数据倾斜问题Hive性能考察点数据开发笔试里的SQL题有时候不会只让你写代码还会写一句“表数据量很大怎么优化”。最常问的就是数据倾斜。所谓数据倾斜就是某些key的数据量特别大导致Reduce阶段一个任务处理了99%的数据其他任务闲等最后整个任务跑得很慢甚至OOM。典型场景和解决思路包括空值引发的倾斜比如一堆join key是null全跑到一个reduce。解法是把空值加上随机后缀比如concat(null_, rand())让它们分散到不同reduce。热点key倾斜比如双十一当天的某个商品访问量极大。解法是加盐随机前缀先聚合一次然后再去前缀做二次聚合。mapjoin优化如果一个小表Join一个大表可以使用mapjoin把大表广播到map端避免Shuffle。Hive中可以通过set hive.auto.convert.jointrue自动优化但笔试时最好能手写/* mapjoin(t) */这个hint。这种优化题没有标准答案但考官想听到的其实就是“你知道存在这样一个问题并且能说出至少一种解决方案”。你如果能在笔试的SQL注释里主动说明“这里考虑到了数据倾斜我会用mapjoin优化”会显得你比普通考生高一个段位。3. 数据仓库与离线计算核心概念题3.1 数仓分层为什么重要京东的笔试题里一般会有一道数仓建模题常见问法是“简述数据仓库的分层结构以及每层的作用”。这题表面简单但很多人的回答是背出来的没有理解分层背后的成本权衡。业界通用分层是ODS操作数据存储层、DWD明细数据层、DWS汇总数据层、ADS应用数据层。ODS层基本是原样同步业务库保持历史状态不修改DWD层做清洗、规范化、维度退化把数据变成更易用的明细模型DWS层按主题做轻度汇总比如按用户日汇总、按商品日汇总ADS层直接面向报表和应用粒度比较粗。为什么不能把所有逻辑都放在一层做我自己的体会是分层是为了控制复杂度和成本。不加分层所有报表都直接查ODS原始日志你得在每个SQL里重复处理脏数据、重复join几十张表开发效率极低出了问题还不好排查。有了DWD层脏数据问题在源头解决一次后面所有人都受益。DWS层把高频汇总指标提前算好报表查询速度会快很多。虽然分层会增加存储和调度成本但换来的是研发效率和系统稳定性这笔账在大厂里算得过来。3.2 事实表与维度表如何选择数仓建模题里另一个必考概念是事实表和维度表。最简单直白的区分事实表是业务过程产生的“行为记录”比如订单事实、支付流水里面主要是可加性的数值度量金额、数量维度表是描述业务对象的“属性集合”比如用户维度、商品维度、时间维度里面是文本描述和分类。笔试时经常给一个场景让你设计订单事实表和商品维度表。这里有一个易错点商品名称、商品类目属于维度信息不应该放在订单事实表里应该通过商品id关联。但在真实数仓开发里为了查询性能会在DWD或DWS层做“维度退化”把常用的商品名称、店铺名直接冗余到事实表里。这种做法违反范式却符合数仓建模的实践精神。所以面试官问“事实表能不能冗余维度字段”你不能直接说不能要能讲清楚什么时候该冗余、什么时候不该冗余。拉链表也是数仓高频考点。当我们要维护一个不断变化的维度比如用户的会员等级、收货地址不能用全量快照浪费存储也不能只保留最新状态丢失历史这时候就用拉链表。拉链表给每行记录增加start_date和end_date两个字段表示这条记录的有效期。当数据发生变化时把旧记录end_date更新为变化前的时间再插入一条新记录start_date为变化时间end_date设为未来日期比如9999-12-31。写拉链表的SQL在笔试里最后一道题出现概率很高。核心逻辑是用增量数据关联历史全量数据找出哪些字段发生变化把变化的旧记录关闭新记录插入。很多人的解答能做到这一步但容易忽略“如果一天内同一用户状态变了多次怎么处理”这个问题。实际生产里我们一般只会拿当天最新快照去更新不会处理一天内的多次变化因为业务方通常不关心这个粒度。如果题目没说清楚尽量在答案里补充一句假设能体现你的思考深度。3.3 Hadoop生态原理题MapReduce与HDFS数据开发笔试里会出一些基础原理题比如MapReduce的详细执行流程、HDFS写文件的流程。这类题占分不算太多但是如果你答得不好容易让面试官质疑你的基本功。MapReduce执行流程的记忆可以分四个阶段Map阶段、Shuffle阶段、Reduce阶段。Map阶段从HDFS读取数据按行解析成key-value执行map逻辑输出中间结果。Shuffle阶段细分为分区、排序、溢写、合并、拉取、归并排序几个小步骤中间数据的key会按分区器分发到对应的reduce任务同时按key排序。Reduce阶段拿到所有中间结果后再对每个key调用reduce函数输出结果写入HDFS。很多人容易把Shuffle理解成“从map传到reduce”的简单过程但实际它有复杂的磁盘IO和网络传输。笔试如果让你设计一个优化方案第一反应可以是从源头减少Shuffle数据量比如使用combiner进行map端合并或者调整mapreduce.job.reduces来控制reduce数量。HDFS写流程也是经典题。客户端向NameNode发起写请求NameNode检查权限和路径后返回可以写入的DataNode列表客户端按块默认128MB将数据分包发送到第一个DataNode第一个DataNode再复制给第二个第二个复制给第三个然后逐级返回ack最后客户端关闭流写操作完成。这里的关键点是“流水线复制”和“收到所有ack才认为写入成功”这保证了数据的多副本一致性。我自己的建议是不要死记硬背你可以把HDFS想象成一个快递仓库NameNode是库管员只记录每个包裹放在哪个货架DataNode是货架本身。客户端存东西时先问库管员库管员分配几个货架客户端依次把货放进第一个货架第一个货架再复制到第二个这样即使一个货架塌了东西还在。有了这个画面面试时描述细节就不容易卡壳。4. 算法与数据结构在笔试中的出题方式4.1 手写排序快排和堆排是常客数据开发笔试的代码题不会只有SQL还会有一两道编程题往往让手写经典排序、链表反转、TopK这类。尤其在时间限制下很多人掉进“用库函数”的坑里——用Collections.sort()确实能过题但面试官问一句“排序原理是什么”就哑火了。快速排序算是最高频的考察点因为它和分布式里的“分治”思想一致。手写快排的关键在于partition函数的稳定性需要把小于基准值的放左边大于基准值的放右边然后递归。这里注意别把边界处理错我建议用双指针写法不容易越界。private int partition(int[] arr, int left, int right) { int pivot arr[right]; int i left; for (int j left; j right; j) { if (arr[j] pivot) { swap(arr, i, j); } } swap(arr, i, right); return i; }堆排序在数据开发里同样重要因为TopK问题最典型的解法就是维护一个大小为K的小顶堆或大顶堆。笔试手写堆排序对很多人来说有点难度但至少要把adjustHeap写对或者能够用Java的PriorityQueue完成TopKPriorityQueueInteger heap new PriorityQueue(k); for (int v : nums) { if (heap.size() k) { heap.add(v); } else if (v heap.peek()) { heap.poll(); heap.add(v); } }求最大的K个数用小顶堆堆顶是堆中最小元素当新元素比堆顶大时替换。这个思路比全量排序空间复杂度低非常多特别适合“海量数据求TopK”这种场景。4.2 海量数据经典题100GB文件求高频词这类题是笔试的“压轴大题”也是数据开发岗区别于后端岗的独特题目。题目通常长这样给定一个100GB的文件每一行是一个字符串求出现次数最多的100个词机器可用内存只有2GB。正确的解法分三步走哈希分片、统计、合并。第一步用hash(word) % M把大文件拆分成M个小文件这里的M要保证每个小文件能加载进内存比如拆成200个每个500MB2GB内存可以装下。第二步对每个小文件单独用HashMap统计词频得到每个小文件内部Top100。第三步将每个小文件Top100汇总到一起用一个包含词频的堆或者MapReduce思想做全局Top100。这道题考察的是你对“分治法”的理解和MapReduce是同一个思路。很多人答到最后只想到用堆却忽略了分片这样在2GB内存限制下直接就OOM了。还有人在回答里说用字典树Trie树虽然也是方案但相对复杂面试官不一定喜欢最稳妥的普适答案还是hash分片堆。如果题目进一步问“怎么保证相同词一定分到同一文件”答案是hash函数有确定性相同字符串的hash值相同取模结果也一定相同。这是一个低概率出错但重要的细节最好在答案里主动讲出来证明你理解原理而不是背答案。4.3 布隆过滤器面试官想听你说出“允许误判”除了海量TopK布隆过滤器也是数据开发方向的高频概念题通常结合“如何快速判断一个URL是否已经被爬取过”或者“如何判断用户ID是否存在”来问。布隆过滤器是一个很节省空间的概率型数据结构通过多个哈希函数把元素映射到一个二进制位数组中。查询时如果任意一个哈希位置的bit为0则一定不存在如果都为1则可能存在有一定误判率。笔试答题时的加分点是主动说明它有两个特性有误判率、不能删除元素。不能删除的原因是一个bit位可能被多个元素共享置0会影响其他元素。通常解法是使用计数布隆过滤器但会增加存储开销。如果你能把“为什么不能删除”讲清楚面试官会觉得你真的理解数据结构的本质而不是简单背概念。5. 编程题与工程能力的考察5.1 语言基础Java/Python/Scala怎么选笔试时编程题一般支持多语言但建议用自己最熟的。数据开发岗在Java和Python之外还会用Scala校招笔试里用Scala的人比较少如果是Spark方向可能会给Scala题。不过我更建议在笔试时用Java或Python因为阅卷人更熟悉出错的概率也小。Java里高频考察点是集合类、HashMap的原理、多线程和IO。比如HashMap的put流程、扩容机制、为什么并发环境下不安全。Python里一般是列表字典的用法、推导式、装饰器这类。Data开发岗的笔试不会考特别偏的语法但会结合场景比如写一个脚本从日志中提取特定字段并统计频率。这里有个实用经验写Python统计词频千万避免在循环里用count()这种O(n²)写法数据量一大根本跑不动。正确思路是用collections.Counter或者手动字典计数from collections import Counter counter Counter() with open(data.txt) as f: for line in f: word line.strip() counter[word] 1虽然很简单但很多同学会写错比如在with缩进上栽跟头。笔试环境不会给提示缩进错了就是编译错误。5.2 从手写代码到工程思维任务幂等与重跑实话讲数据开发工程师日常很少手写排序算法更多是在写ETL任务和调优SQL。那笔试为什么还要考编程题因为它想看到你写代码的条理和边界意识这直接影响你在生产环境里的代码质量。比如笔试如果你写一个函数要考虑到输入为空会怎样数据量特别大会怎样异常的日志怎么打。如果能主动写出“空值处理”、“异常捕获”这个代码的水平就上了一个档次。更高级的考察方式是让你设计一个离线任务流。比如给定业务数据需要每天凌晨从RDS全量同步到HDFS然后做清洗再产出报表你会怎么设计调度这题的要点是保证任务可重跑、数据不重复。我们一般会在ODS层加分区以当天日期作为分区如果任务失败重跑直接覆盖当天分区不产生重复数据。同时在DWD层计算时对上游分区做确认如果上游数据未就绪则等待重试。工程思维的另一个关键是“幂等”。一个任务重复跑两次结果应该一致。离线任务通常通过insert overwrite table ... partition(dt2024-01-01)保证幂等实时任务则更复杂需要利用唯一键去重。笔试题里如果涉及输出方案主动提“保证幂等”绝对是加分项。5.3 Shell及常用的数据开发工具笔试偶尔会有一两道Linux/Shell题比如查找大文件、统计日志行数、crontab设置。很多人忽略这部分但数据开发不可能不开服务器会写简单的Shell能体现落地能力。高频命令包括grep、awk、sed、sort、uniq -c、head/tail。比如统计日志中每个IP出现次数一条命令就是awk {print $1} access.log | sort | uniq -c | sort -rn | head -10这里容易出错的点是uniq只能合并连续的重复行所以必须先sort再uniq。这道题几乎每年都有人栽就是因为调换了顺序。如果你能在笔试里把这个命令解释清楚再顺手写一个等价Python脚本会让阅卷人觉得你基础扎实。6. 面试准备避坑指南与经验心得6.1 我当年踩过的坑我第一次做这套题时SQL部分写了很长结果跑都没跑。后来复盘发现问题出在“只写不测”上。笔试时编辑器没有运行环境你写出来的SQL全靠脑子编译但逻辑哪里有问题很难发现。所以现在我给所有准备笔试的同学一个建议平时练习一定要在本地装个MySQL或者用Hive/Spark环境把每道题亲手跑一遍尤其是窗口函数和连续问题不跑一遍你根本不知道坑在哪。另一个坑是“背题不挖原理”。比如我背过MapReduce流程和HDFS写流程但面试官追问“为什么edits文件要放在NameNode本地磁盘”我一愣。笔试答对是第一步你要准备把每个答案延伸出三个“为什么”。这些年我自己做面试官时最反感的就是候选人答得像百科词条一问细节就卡住。还有一个坑是时间分配。笔试题量不小有单选、多选、SQL大题、编程题。我当年在单选辨析题上花了很多时间导致后面的大编程题时间不够只写完大概框架。后来学聪明了拿到卷子先花两分钟看完整体分值优先保证SQL大题的完成度因为一道SQL题的分值通常超过好几道选择题。笔试时间短策略比蛮力更重要。6.2 常见问题速查表高频问题核心思路常见踩坑分组TopN窗口函数row_number/rank/dense_rank过滤窗口函数时未包一层子查询连续登录日期减去行号构建分组键忘记去重、同一天多条记录数据倾斜空值加随机后缀、热点key加盐、mapjoin只想到调参数不提具体场景数仓分层每层职责明确控制复杂度说不清每层典型表拉链表开始日期结束日期不处理一天多次变化海量数据TopKhash分片堆没提内存限制对分片数的影响布隆过滤器多hash到位数组忘了说误判率和不能删除Shell统计词频sort后再uniq无脑用uniq导致结果错误这张表里的内容是整个数据开发笔试的核心骨架建议你在复习时对着表格逐一自测能不看答案把每行完整讲清楚再去刷题效果会好很多。6.3 最后一件事别忽略“讲思路”的能力虽然这是笔试题不是面试题但有些大厂的在线笔试会有一道“只要写文字”的题目让你描述方案。比如“请设计一个日活用户统计方案”或“某个SQL跑了3小时还没出结果排查思路是什么”。这类题没有标准答案但能看出你的思路是不是完整的。我自己习惯用“分情况讨论”的方法来答。先问清楚统计口径日活是按登录去重还是按设备去重再提数据来源从业务库同步还是从埋点日志算然后说技术选型离线用Hive/Spark实时用Flink最后补充异常处理如果上游数据晚到怎么办如果数据对不上怎么排查。这四块一展开即使细节不完美整体也已经是一套合格的工程方案。最后再给大家一个非常实际的建议准备笔试前一定要建立一个自己的本地练习环境。不一定要很强的服务器装个Docker里面起个MySQL或者Hive把你在牛客和历年真题里遇到的SQL题都跑一遍。我之前帮人改题最大的感受是很多人不是不懂解法而是语法细节错误太多比如字段别名不写as、group by漏字段、left join写成交叉join这些在真实环境一执行立刻暴露。笔试没有试错机会所以平时多跑形成肌肉记忆才是稳的。
返回列表