十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

掌阅大数据开发岗笔试复盘:从SQL窗口函数到数仓实战

掌阅大数据开发岗笔试复盘:从SQL窗口函数到数仓实战 2023年秋招季我投了掌阅科技的大数据开发岗笔试做完之后最大的感受是这家公司考的东西不算偏但非常务实几乎每一道题都能在真实的数仓和用户增长业务里找到对应场景。如果你正在准备类似岗位这份复盘应该能帮你少走不少弯路。先说下整体情况。掌阅的笔试时间是90分钟题量不算大大约30道选择题加3道主观题但内容覆盖面比较广从SQL窗口函数、Hadoop生态组件原理到Java集合源码、机器学习基础概念都有涉及。没有纯考背诵的八股更多是给你一个业务场景让你用技术方案去解决。这点和很多纯互联网大厂的出题风格不太一样更偏向“你是不是真的拿数据干过活”。整份卷子做下来我的体感是SQL和Hive占了大头Spark和Flink也有涉及Java基础考得比预期多算法题反而比较朴素——没有hard级别的动态规划重点在思路上。1. 笔试全景与岗位定位1.1 掌阅大数据岗到底在招什么样的人先说岗位定位。掌阅做数字阅读起家核心产品是掌阅App和iReader阅读器业务数据主要来自用户阅读行为、付费转化、内容推荐效果、广告投放等场景。所以大数据岗的日常工作大概率围绕这几块用户行为日志的清洗与建模、内容推荐的特征工程、阅读时长的多维分析、会员付费漏斗的转化洞察。从这个业务形态反推笔试内容就能理解为什么SQL和数仓占据了那么多篇幅。阅读类产品的数据链路非常典型客户端埋点 - 日志服务 - 消息队列 - 数仓分层 - 报表和推荐特征。笔试里的题目本质上就是在模拟这条链路上的实际问题。如果你准备投这家公司建议先把用户行为分析、漏斗转化、留存分析这几类SQL场景刷熟比盲目刷leetcode性价比高得多。我在考场上看到好几道题第一反应就是“这不就是我们数仓日常取数的活儿”。1.2 题量与时间分配策略90分钟做30道选择加3道主观题时间看上去宽裕但实际上主观题非常耗时间尤其是让你写SQL和画架构图的那种一不小心就容易超时。我的建议是选择题控制在40到45分钟内剩下45分钟全部留给主观题。选择题的分布大概是这样的SQL和数据仓库相关约8到10道Hadoop生态组件HDFS、MapReduce、YARN、Hive约6到8道Spark和Flink约4到5道Java基础约4到5道机器学习基础约2到3道。这个比例说明掌阅对数仓和离线处理能力的要求很高实时计算也有涉及但对算法深度要求不算夸张。做题顺序上我个人的习惯是先扫一遍所有题目把会做的快速搞定拿不准的标记下来最后再回头思考。这样能避免在一道卡壳的题上耽误太久导致后面的简单题没时间做。2. 核心考点拆解SQL和数仓题2.1 窗口函数是绝对重点SQL题里窗口函数几乎必考而且不是简单的row_number() over这种入门用法而是会组合排序、聚合、偏移函数一起考。我记得有一道题大概是这样的给定用户阅读记录表reading_loguser_id, book_id, chapter_id, read_time, device_type要求统计每个用户连续阅读天数大于等于3天的用户名单。这道题有两个关键点。第一同一天可能有多条阅读记录所以要先对user_id和日期去重。第二要判断连续天数经典解法是用日期减去row_number()的分组偏移连续日期的差值相同形成一个新的分组标识然后按这个分组标识统计天数。我当时在考场上写的大致思路是这样的with user_daily as ( select distinct user_id, to_date(read_time) as read_date from reading_log ), user_seq as ( select user_id, read_date, date_sub(read_date, row_number() over (partition by user_id order by read_date)) as grp from user_daily ), user_group as ( select user_id, grp, min(read_date) as start_date, max(read_date) as end_date, count(*) as cnt from user_seq group by user_id, grp ) select distinct user_id from user_group where cnt 3;这里date_sub(read_date, row_number())是判断连续日期的核心技巧原理是如果日期是连续的那么每个日期减去它在该用户日期序列中的排序编号结果一定是同一个值。一旦中断这个差值就会变化。理解这个原理比背代码重要因为题目换个花样比如求最长连续登录天数、连续付费天数思路是一样的。2.2 留存分析和漏斗转化留存率和漏斗转化是运营和产品最常看的两类指标笔试里自然不会少。掌阅的题目考了次日留存的计算给了用户活跃表和阅读行为表要求算不同注册渠道的新用户次日留存率。核心逻辑是先找到某天新增的用户集合然后判断这些用户在次日是否有活跃行为最后按渠道分组计算比例。这里有个容易踩坑的地方——次日留存的“活跃”定义题目里可能同时包含启动App和阅读行为两种口径一定要看清楚题目要求的是哪种。我看题时就差点把“阅读行为”和“启动行为”混在一起算。漏斗转化题也很有代表性模拟的是从App启动到完成首次阅读的转化链路启动 - 浏览书籍详情 - 加入书架 - 开始阅读。要求计算每一步的转化率并找出转化率最低的环节。这类题除了写SQL还可能让你给出优化建议这时候如果你能结合阅读类产品的特点比如“加入书架到开始阅读的转化低可能是因为阅读器打开速度慢”或者“书籍详情页缺少试读章节导致跳出率高”会比只写SQL的人高一个段位。2.3 数仓建模理论题主观题里有一道数仓设计题背景是掌阅要做一个“用户阅读行为分析”主题的数仓要求设计分层架构并说明各层职责。这道题其实考的就是你对数仓分层的理解程度。我当时的回答思路是这样的ODS层存放原始日志保持和埋点数据一致不做过多加工DWD层做清洗和标准化比如解析user_agent得到设备型号和操作系统版本统一时间格式过滤爬虫和异常数据DWS层按主题汇总比如用户维度的阅读时长、阅读天数、付费金额等指标ADS层面向具体业务场景输出比如推荐算法的特征表、运营看板的指标表。这里的关键是强调“为什么这样分层”。ODS保持原样是为了回溯和排查问题DWD清洗标准化是为了下游复用DWS汇总是为了减少重复计算ADS按需组装是为了快速响应需求。每一层都有自己的职责边界不能混在一起。面试官想听的往往不是你背出的分层名称而是你对每一层存在理由的理解。3. 核心考点拆解Hadoop生态与Java3.1 HDFS写入流程与副本策略HDFS相关题目里写入流程是必考题。题目一般这么问客户端往HDFS写一个文件从调用create接口开始到数据落盘整个过程是怎么运作的副本策略又是怎么选择的回答要点是这样的客户端先调用DistributedFileSystem.create()这个请求会发送到NameNodeNameNode检查权限和目录是否存在然后在文件系统元数据里创建文件条目返回一个FSDataOutputStream给客户端。客户端开始写数据时会把文件切分成块默认128MB第一个块写完后DataNode之间会建立管道Pipeline按副本因子默认3依次把数据复制到下一个节点。副本放置策略在默认情况下是第一副本放在客户端所在节点如果客户端不在集群内则随机选一个磁盘空间充足的节点第二副本放在与第一副本不同机架的节点第三副本放在与第二副本相同机架的不同节点。这样设计是为了在可靠性和写入性能之间取平衡——机架内带宽充裕跨机架复制保证容灾如果三个副本都放同一个机架整个机架断电数据就全没了。笔试里还考了一个小问如果写入过程中某个DataNode挂了会怎样答案是管道会关闭已经写入的块信息会重新上报给NameNodeNameNode会重新分配一个DataNode作为新的复制目标客户端会从失败的块位置重新尝试写入。这个机制保证了写入的高可用但也意味着写入延迟会有所增加。3.2 Spark作业执行流程与宽窄依赖Spark的题目明显比Hadoop更深入毕竟现在离线计算大部分都跑在Spark上。我记得有一道题是描述Spark作业从提交到执行的完整流程关键在于理解Driver、Executor、DAG调度器、TaskScheduler之间的协作关系。流程是这样的用户提交Spark作业后Driver会创建SparkContextSparkContext向Cluster Manager申请Executor资源。作业中的Action操作会触发DAG的构建DAG Scheduler负责把作业拆分成多个Stage划分依据是宽依赖——遇到shuffle操作就切分Stage。每个Stage内部包含多个可以并行执行的TaskTaskScheduler把Task分发到Executor上执行。这里宽窄依赖是个高频考点。窄依赖是指父RDD的每个分区最多被一个子RDD分区使用比如map、filter、union操作可以在同一个Stage内完成不需要shuffle。宽依赖是指父RDD的每个分区可能被多个子RDD分区使用典型的就是groupByKey、reduceByKey、join这类操作必然产生shuffle也是Stage划分的临界点。理解这个区别的价值在于——一个作业写得好不好很大程度上就是看你能不能尽量减少宽依赖。3.3 Flink的state和checkpoint机制实时计算部分Flink主要考了状态管理和checkpoint机制。题目大概是这样在Flink流式计算中状态State的作用是什么checkpoint是怎么实现的State是Flink实现有状态计算的核心。比如统计每个用户每分钟的阅读时长你需要一个Map来保存中间结果这个Map就是State。Flink的State分两种算子状态Operator State和键控状态Keyed State。键控状态按照key进行分区每个key有自己的状态适合做按用户维度的统计。Checkpoint机制是Flink容错的关键。它基于Chandy-Lamport分布式快照算法通过Barrier屏障实现。Source算子周期性地向流中注入Barrier每个算子收到Barrier后保存自己当前的状态快照然后将Barrier传递给下游算子。当所有算子的快照都保存完成后一次checkpoint就完成了。这道题的考点不在于背概念而在于理解状态和checkpoint之间的关系——状态保存在本地可以是内存、RocksDB等checkpoint则是把状态定期备份到外部存储比如HDFS来保证故障恢复能力。一旦某个Task失败Flink可以从最近一次成功的checkpoint恢复状态重新开始处理数据。3.4 Java基础题Java基础考得比较常规主要是集合类源码和并发编程。有一道题是HashMap的put流程和扩容机制这个是Java八股里的经典题了——计算key的hash值通过扰动函数(^和)降低碰撞概率定位到桶位后如果桶位是链表就尾插如果链表长度达到8且数组长度达到64就转成红黑树扩容时数组长度翻倍元素会重新分配位置。还有一道题是问synchronized和ReentrantLock的区别以及volatile的作用。这些题对专门准备过Java面试的人来说算送分题但如果你的主攻方向是纯大数据开发平时不怎么写Java代码这些题可能会丢分。我建议准备大数据岗的时候Java基础别完全丢掉HashMap、ConcurrentHashMap、线程池这三大件一定要能说出来。4. 核心考点拆解机器学习与算法4.1 机器学习基础概念掌阅笔试里机器学习题目不多但考得比较典型。有一道题是问过拟合的解决方法选项包括增加训练数据、正则化、Dropout、交叉验证、减少模型复杂度。这道题基本是送分题全部选项都是对的。还有一道题考了特征选择的方法给出了一些选项让你判断哪些属于过滤式、包裹式、嵌入式方法。这里的关键是理解三类方法的区别过滤式方法Filter独立于学习算法根据统计指标卡方检验、信息增益、相关系数等筛选特征包裹式方法Wrapper把学习器性能当作特征子集的评价标准典型有递归特征消除嵌入式方法Embedded在学习器训练过程中自动进行特征选择比如L1正则化、决策树的特征重要性。我看到这几道题的时候有点意外因为不少大数据岗笔试完全不碰机器学习但掌阅考了。后来想想也合理——推荐系统是阅读类产品的核心特征工程和模型训练都要用到这些基础知识了解基本概念可能是对岗位的基础要求。4.2 算法题不靠难题靠思路算法题部分比较友好考了一道SQL转化的题目给定整数数组找出和为target的两个数的下标。这题用HashMap一次遍历就能解决时间复杂度和空间复杂度都是O(n)。public int[] twoSum(int[] nums, int target) { MapInteger, Integer map new HashMap(); for (int i 0; i nums.length; i) { int complement target - nums[i]; if (map.containsKey(complement)) { return new int[] {map.get(complement), i}; } map.put(nums[i], i); } return new int[] {-1, -1}; }还有一道是字符串相关的题大概是判断括号是否有效用栈来处理就行。整体来说算法题难度低于大厂校招常规水平但是要注意代码的完整性和边界条件。比如twoSum不仅要考虑有解的情况还要考虑无解时返回什么。我的体感是掌阅的算法题更偏向验证“你能否把思路用代码落地”而不是考察你是否有竞赛级别的算法能力。如果你的算法基础一般把常见的哈希表、双指针、栈、队列、二叉树遍历这些高频题型刷熟问题就不大。5. 主观题深度拆解场景设计题5.1 阅读行为分析数仓设计主观题第一道是数仓设计题题干给了场景掌阅App每天产生数亿条用户行为日志需要构建一个行为分析数仓支撑运营看板、用户画像、推荐系统三个业务方向。要求给出数仓分层架构、核心表设计以及ETL调度方案。这道题考察的是综合设计能力。我的思路是先把三个业务方向的需求拆清楚运营看板需要统计类指标DAU、MAU、人均阅读时长、付费率用户画像需要标签类数据性别年龄、阅读偏好、消费能力推荐系统需要特征类数据用户实时行为序列、书籍内容特征。不同需求对数据的时效性和粒度要求不同数仓分层也要相应考虑。在表设计层面DWD层我建议按主题拆分为用户主题、书籍主题、行为主题。用户主题表包含用户注册信息、设备信息、渠道来源等书籍主题表包含书籍基本信息、分类、标签、上架时间等行为主题表包含阅读行为流水字段包括user_id、book_id、action_type、from_page、to_page、duration、timestamp等。DWS层按天汇总用户维度的阅读指标ADS层分别输出运营看板和推荐特征需要的数据。ETL调度可以用DolphinScheduler或者Airflow来实现核心是管理好任务依赖关系——ODS层同步完成之后才能跑DWD层清洗任务DWD层完成之后才能跑DWS汇总任务。调度频率方面离线任务一般按天T1调度实时看板的需求则走Flink实时计算链路。5.2 日志采集链路设计第二道主观题是设计一个日志采集与处理链路场景是App端需要上报用户行为日志包括启动、浏览、点击、阅读等事件要求设计端到端的数据链路并说明各组件选型理由。这道题其实就是考察你对大数据生态各组件的理解和选型能力。链路大概是这样的App端通过埋点SDK采集日志通过HTTP或者TCP长连接上报到Nginx集群Nginx做负载均衡和接入层缓冲然后写入Kafka消息队列。下游有两个分支离线链路通过Flume或Canal将Kafka数据同步到HDFS再用Spark/Hive做批处理实时链路通过Flink消费Kafka进行实时ETL和指标计算结果写入ClickHouse或者Doris供实时查询。链路设计本身不难难的是说清楚每一步为什么选这个组件。比如为什么中间一定要加Kafka答案是削峰填谷——晚上8点是阅读高峰期日志量可能是白天的数倍如果没有消息队列缓冲直接写入HDFS或数据库很容易把下游打爆。Kafka的高吞吐和消息持久化能力能够在上游流量突发和下游处理能力之间起到缓冲作用。再比如实时计算为什么选Flink而不是Spark Streaming虽然Spark Streaming的微批模式也能实现准实时但Flink在事件时间处理、状态管理、精确一次语义方面更成熟对于阅读行为这种需要精确统计的场景更合适。5.3 用户留存下降的分析框架第三道主观题比较有意思题干是某个月发现掌阅App的用户次日留存率下降了5个百分点要求设计分析方案找出可能的原因。这是一道开放性问题答案没有唯一标准但很能反映一个人的数据分析思维水平。我的回答框架是这样的首先从数据层面确认下降趋势——是整体下降还是某个渠道、某个版本、某个用户群体在下降然后从多个维度拆解包括版本维度最近是否有新版本发布、渠道维度是否有渠道投放质量下降、内容维度是否有头部书籍下架或推荐策略调整、竞品维度是否有竞品在同期做大规模推广、季节维度是否受寒暑假周期影响。接下来要定位到具体环节用漏斗分析对比留存下降用户与留存正常用户在关键行为上的差异比如新用户是否完成首次阅读、是否完成书架添加、是否收到有效的推送触达。还可以做同期群分析Cohort Analysis把不同周新增的用户分开对比看是新增用户质量下降还是老用户活性下降。最后要结合外部信息辅助判断——比如去应用商店看最近版本的评分和用户评论去看竞品动态去看是否有重大舆情事件。分析思路的价值在于它体现的不是SQL写得好不好而是遇到业务问题时能否体系化地拆解这恰恰是大数据岗位和纯技术研发岗位最大的区别。6. 复盘总结与备战建议6.1 从笔试题反推掌阅的技术栈做完这份笔试题大致可以反推出掌阅大数据团队在用什么技术栈。HDFS、Spark、Hive是离线计算的主力Kafka是消息队列的标准配置Flink用于实时计算场景数仓建设已经走上分层规范化的路线ClickHouse或Doris在实时报表查询中应用广泛。如果准备后续的面试建议重点关注几个方向一是SQL能力特别是窗口函数、UDTF、复杂JOIN的性能优化二是数仓建模方法论尤其是维度建模中的星型模型和雪花模型的适用场景三是Spark调优经验比如数据倾斜的解决方案、小文件问题的治理、Shuffle优化的常用手段。6.2 给准备者的实战建议回头看这份笔试题我给准备掌阅或者其他互联网公司大数据岗的同学几个具体的建议。第一SQL一定要非常熟练达到能用窗口函数解决任何常见业务问题的程度。我推荐的练习方式是找一个真实的业务数据集给自己设定分析场景比如计算用户留存、转化漏斗、复购率、TOP N排行榜、连续N天活跃等把每种场景的SQL都写一遍写熟练。不要只刷题不思考遇到问题时问问自己如果数据量放大一百倍这条SQL还能跑得动吗第二Hadoop生态的组件原理不要死记硬背要理解设计动机。面试官问“HDFS为什么不适合存小文件”如果你能说出“小文件会导致NameNode内存占用过高、MapReduce启动Task的开销变大、数据本地性变差”这三个层次的原因就比单纯背诵答案要让人信服得多。第三主观题部分一定要把思路写清楚不要只写结论。比如数仓设计题你要画出分层架构图写明每一层的输入输出和职责边界说明为什么这样设计有什么权衡取舍。阅卷人看的不是标准答案而是你的思维过程和工程素养。第四算法题虽然难度不高但不能掉以轻心。手写代码要保证能够一次性run通过注意边界条件、空值判断、极端输入的处理。平时练习的时候不要用IDE自动补全尝试在白板或者纯文本编辑器里写模拟笔试环境。6.3 考后的一些体会说实话考完掌阅这套题我最大的感受是它更看重“数据工程师”的综合素养而不是某一项技能的深度。SQL要熟练大数据组件要有全局视野Java基础不能丢业务理解也要有——这些都是日常工作中真正常用的东西。有一道题我印象特别深问的是Kafka消费者组的rebalance机制。候选人如果只是背过“消费者加入或退出时会触发rebalance”但没有真正处理过线上rebalance导致的消费延迟问题回答的深度会有明显差别。如果你在一线工作过就会知道rebalance过程中所有消费者会暂停消费这会导致消费位移停滞消息积压严重时还会造成重复消费。这种“实战型”考点在掌阅笔试里不是个例。整体试卷传递的信号很清楚我们不要只会写SQL的取数工具人也不要只会调参调的算法工程师我们要的是能用数据手段解决业务问题的工程师。想明白这一点笔试的备考方向也就清晰了。
返回列表