ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

蚂蚁工程数据挖掘岗笔试全解析:从特征工程到SQL优化

蚂蚁工程数据挖掘岗笔试全解析:从特征工程到SQL优化 2024年秋招那阵子我投了不少大厂的数据挖掘岗蚂蚁集团的工程数据挖掘岗笔试是其中印象很深的一场。和很多公司线上笔试只考选择题不同这场笔试明显更偏向工程落地能力和数据敏感度的结合题目不多但每一道都要写实质性的方案和代码三个小时下来比连续开四个需求评审会还累。这篇文章我就把当时梳理的考点、回忆版题目、解题思路和踩过的坑完整写出来给接下来冲这个方向的朋友做个参考。1. 笔试整体风格与考察逻辑1.1 岗位定位决定出题方向先说结论蚂蚁的工程数据挖掘岗重点不在“挖掘”两个字而在“工程”两个字。字面上看数据分析、特征工程、模型训练都会涉及但笔试真正想筛选的是那种能把数据挖掘方法稳定、高效、低成本地落到工程链路里的人。它不是招一个研究型人才也不是招一个纯平台开发而是招“能用算法解决实际业务问题、同时能扛住工程落地压力”的人。所以你在准备这个岗位时如果只刷机器学习理论题和Kaggle套路大概率会栽。笔试里既不会让你手推SVM对偶也不会让你调参炼丹更多是给你一个业务场景、一份不干净的数据让你去设计挖掘方案、给出特征体系、写出核心代码并说明如何上线、如何监控、如何迭代。1.2 题型结构与时长远超预期我参加的那场笔试时间是180分钟题量不大一共4道大题全部是问答题加手写代码的综合题。没有选择题没有填空题没有客观题。这意味着你没法蒙也没法靠练习题的肌肉记忆混过去每一道题都需要现场组织逻辑、写方案、写代码、画流程用文字描述最后还要给出评估方式和潜在风险。很多人一看题量大不大先看数字觉得4道题不难。但实际做起来每道题都像一个小型答辩你不仅要给出答案还要给出“为什么这么选”必要时还得比较不同方案的优劣。我在第二道题上写了将近1000字的方案论证最后还剩30分钟时发现第四道题还没碰差点翻车。所以时间分配非常关键后面会专门说。1.3 与常规数据挖掘笔试的差异对比这里我拿之前面过的其他几家公司笔试题做了个对比帮大家更直观感受差异对比维度蚂蚁工程数据挖掘岗普通数据挖掘岗笔试题型综合问答手写代码选择简答代码侧重点工程可行性、方案设计算法原理、模型效果数据特征脏数据、真实业务字段相对干净的数据集代码题强调效率、容错、可上线强调实现正确、通过用例考察思维如何落地、如何监控如何调参、如何提分这个对比不是绝对但能说明一个大方向如果目标是蚂蚁这种级别的大厂工程数据岗位至少要把“从数据到模型到上线到监控”这条链路完整走一遍不留死角。2. 核心考点拆解数据预处理与特征工程实战2.1 第一道题用户行为日志清洗与聚合第一道题就是一个非常接地气的场景。具体题目大概是给你一份用户在小程序上的行为日志包含字段用户ID、行为类型点击、曝光、加购、支付、行为时间戳、页面ID、商品ID、停留时长、操作系统、网络类型。日志量级很大可能有几亿行存储在Hive表中。要求你清洗数据并计算“每个用户每天在不同商品类目下的行为序列”同时过滤机器行为最终得到一张可用于后续推荐或画像训练的特征表。这道题看似简单其实至少藏了四个考察点。第一个考察点是数据清洗的完整度。实际日志里一定会有重复记录、字段越界、时间戳单位不统一、行为逻辑矛盾比如还没有曝光却直接支付等问题。如果直接group by特征表必然是脏的。我当时给出的步骤是先做去重按用户ID、行为时间戳、行为类型、商品ID做联合去重再处理缺失值关键行为缺失商品ID的直接丢弃然后检查时间戳合法性时间不能在未来不能早于注册时间最后处理行为顺序矛盾比如“支付”前面没有“点击”和“加购”的记录要么保留并标记异常要么单独建一张异常行为表而不是简单删除。第二个考察点是机器行为识别。题目里特别提到要过滤机器行为这是在真实业务里最常遇到的问题之一。我写的是用滑动窗口统计单用户在1分钟内的行为频率超过阈值比如每分钟大于30次点击就判定为风险账号再结合行为序列的熵值判断如果用户在多个无关类目间高频切换大概率是爬虫或脚本。这里不建议直接删数据正确做法是打标后保留在表里因为后续建模时可能单独分析机器行为的模式。第三个考察点是聚合粒度。题目要求输出“每个用户每天在不同商品类目下的行为序列”这里有个小坑原始日志里只有商品ID没有类目ID。需要先用商品维表join一次把类目带进来。我当时在方案里写了“先窄表join商品表再做用户天类目粒度的聚合”避免在宽表状态下join导致的数据膨胀。这是工程上的一个常用优化面试官会关注。第四个考察点是聚合成序列的方式。行为序列不是简单的计数而是要通过sort by时间戳后collect_list。我用的是Hive的collect_list配合sort_array或者用窗口函数row_number后过滤再按用户ID分组。同时要注意序列长度可能很大如果直接存下游读取会非常慢。我当时建议对序列做截断保留最近50条或者用session切分把行为按照30分钟无操作切分成多个session再在每个session内聚合。这样既保留了行为语义又控制了数据量。这道题我在写代码时没有直接只给一个SQL而是先给了总体的ETL流程再分别写了清洗SQL和聚合SQL。代码量不大但每一步都标注了“为什么这么做”比如“为什么要做三层清洗而不是一层”“为什么过滤机器行为的阈值要可配置”。这一点后来复盘时觉得非常关键。2.2 第二道题不平衡样本下的风险识别特征体系第二道题是典型的金融风控场景和蚂蚁的业务高度相关。题目大概是要用用户的交易行为数据做“套现风险识别”的二分类任务正样本占比极低千分之一级别数据包括交易金额、交易时间、交易对手类型、地理位置、设备信息、历史行为统计等。这道题的核心不是让你训练一个模型而是让你设计一套特征体系并且要给出特征从定义、加工、上线到监控的完整方案。我把这道题的思路分成三个层次。第一层是基础统计特征。围绕每一笔交易衍生出近1/7/30天的交易次数、金额均值、金额方差、夜间交易占比、大额交易次数、同一设备绑定的交易数等。这些特征虽然常见但非常有解释性在风控场景里本身就具备可用的业务含义。比如“夜均占比高”可能意味着异常使用习惯“金额方差小但次数多”可能是拆分交易规避风控的典型模式。第二层是时序特征与序列特征。套现行为通常不是单点行为而是一段时间内的模式。我当时设计了一个“行为熵”将用户的行为序列按交易金额分桶计算熵值熵值越高说明金额分布越分散而套现用户的金额往往集中在某一档位熵值反而会低。还有“周期因子”对同一用户交易间隔序列做标准差和变异系数套现用户往往具有非常规律的间隔比如每周固定某一天、每天同一时间到账后立即转出这种规律性在普通用户身上不会出现。第三层是关系网络特征。题目里没有直接提供用户关系图但给出了设备信息和对手类型。可以利用设备维度做聚类在同一设备上出现过的多个用户ID之间建立关联这种“一机多户”本身就是风险信号。还可以构建“资金汇聚度”看用户的转出对手是否集中在极小数量对手方比如超过90%的转出都发生在同一个对手时套现的嫌疑就大幅增加。这道题的工程难点在于特征计算量大而且需要支持跨天回溯。我的方案是分三层搭建特征层计算方式存储与更新基础统计特征Hive离线批处理天级分区表序列特征Spark按用户时间窗口滑窗离线任务参数化窗口网络特征图计算引擎生成小时级更新避免全量重建我还特意提到了“特征穿越”问题也就是特征计算只能用t-1时刻及之前的数据绝对不能用当天的未来数据。在风控模型里特征穿越会导致模型AUC虚高上线后效果崩塌。这个点虽然在临场答题时很容易漏但我写出来之后明显感觉这道题的完成度上来了。另外针对正负样本极度不平衡我详细写了一个“放弃SMOTE、改用代价敏感学习和模型集成”的理由。原因在于在真实风控场景里合成样本很难捕捉资金转移的复杂性直接过采样容易造成模型对少数类过拟合。代价敏感学习比如在XGBoost里设置scale_pos_weight或者使用Focal Loss既能控制训练分布又能保留原始业务分布。模型层面可以用Bagging加不同样本比例每个子模型用不同采样率最后加权融合这种思路在工程上更稳健。3. 实操过程与核心环节实现3.1 第三道题峰值流量下特征服务的容错设计第三道题彻底脱离了“建模”的范畴转为考察在线特征服务的工程能力。题目原话大概意思是一个高并发的推荐系统每秒钟要处理数十万次特征请求特征数据存储在Redis集群中但部分特征需要从Hive离线表异步更新到Redis部分特征依赖实时计算链路Flink写入。遇到大促高峰时Redis cluster出现大量热key读写同时Flink任务延迟导致部分实时特征无法及时更新。要你设计一个特征服务方案保证高峰期的服务可用性和特征新鲜度。这道题和我以前理解的“数据挖掘”完全不是一回事更像是一个算法工程师和系统工程师的交叉题。我当时看到题愣了一下随后才意识到在蚂蚁这种体量的公司一个数据挖掘工程师如果不懂得特征是怎么被线上服务消费的那么做出来的特征永远只是“离线报表”而不是真正驱动业务增长的动力。我给出的方案主要分四块。第一块是热key治理。先按特征ID和请求来源维度做统计找出Top N热key。然后做本地缓存或者多级缓存在特征服务的JVM里增加一层Caffeine缓存设置合理过期时间比如实时特征3秒、离线特征30秒命中后直接返回不再打到Redis。同时把热key请求做随机后缀拆分成多个key分散到不同分片也就是“热key打散”的常规手段。第二块是降级策略。当Redis不可用或超时率达到阈值时自动切换到本地文件快照或远端只读备份。我设计的是把每天凌晨生成的离线全量特征快照加载到本地如果实时特征超时就用离线值兜底。这样虽然新鲜度有损失但至少服务不挂。这里的关键点是“允许数据降级不允许请求失败”这是我在实际系统设计中学到的核心原则。第三块是实时特征异步更新。Flink延迟是常态不能等Flink写入成功后才返回。我建议在特征服务里暴露出两个字段特征值和特征更新时间戳。模型请求时服务端返回如果模型发现实时特征时间戳太旧则自动退回离线版本。这种“时间戳驱动的一致性模型”比单纯依赖Redis的值更可靠。第四块是流量控制。大促高峰要提前做好压测和容量预估我写了“基于历史峰值的1.5倍水位申请Redis资源”以及“在流量超过阈值时采用随机拒绝一小部分低优请求保护核心链路”的方案。这道题我花了不少笔墨去解释“为什么随机拒绝比排队更好”在高并发下排队会占用线程资源导致整体吞吐下降而直接拒绝很快能让客户端快速重试或走降级路径。这道题写完后我自己都感觉得出来平时如果只专注于训练模型、调参数是不可能答出这种方案的。所以建议后面想面这个方向的同学提前补充一些系统设计知识尤其是缓存、高可用、降级、熔断、消息队列这些基础组件在特征服务里的应用。3.2 第四道题SQL优化与代码实现第四道题是压轴题也是唯二需要手写大量代码的题目之一。题目是给一个日活用户表user_id, dt, active_time, channel和一个订单表order_id, user_id, dt, amount, status要求统计“最近7天内活跃且在最近7天内有成功订单的用户数”并且要求SQL能够在大数据量下高效运行不能跑两个小时那种。这道题看起来寻常但因为我在前面时间分配失控做得很赶反而暴露了一些低级问题。我最初写的是先join再group by如下SELECT COUNT(DISTINCT a.user_id) FROM active_table a JOIN order_table o ON a.user_id o.user_id WHERE a.dt 2024-09-01 AND a.dt 2024-09-07 AND o.dt 2024-09-01 AND o.dt 2024-09-07 AND o.status success这种写法在数据量小时没问题但在超大表上join会导致中间数据膨胀得极其严重而且COUNT(DISTINCT)本身就是一个性能瓶颈。后来我改成先各自去重、再join的写法WITH active_users AS ( SELECT user_id FROM active_table WHERE dt BETWEEN 2024-09-01 AND 2024-09-07 GROUP BY user_id ), ordered_users AS ( SELECT user_id FROM order_table WHERE dt BETWEEN 2024-09-01 AND 2024-09-07 AND status success GROUP BY user_id ) SELECT COUNT(*) FROM active_users a JOIN ordered_users o ON a.user_id o.user_id这样每一层的数据量都已经被压缩到最小再join时就不会有爆炸式膨胀。还有一种更极致的优化方法是使用半连接也就是IN子查询SELECT COUNT(*) FROM ( SELECT user_id FROM active_table WHERE dt BETWEEN 2024-09-01 AND 2024-09-07 GROUP BY user_id ) a WHERE user_id IN ( SELECT user_id FROM order_table WHERE dt BETWEEN 2024-09-01 AND 2024-09-07 AND status success GROUP BY user_id )不过在大数据引擎里这种in子查询的优化程度取决于引擎版本有些引擎会自动转为semi join有些不会所以我当时写了两个版本并说明推荐使用显式semi join。另外我写了一个易被忽略的点订单表要过滤status最好在读取分区时把status作为分区条件或者至少使用分区裁剪避免全表扫描。如果订单表不是分区表而是单层大表建议先做预聚合通过“先过滤再聚合再join”的三段式来降低IO。这道题让我意识到一个很现实的问题很多算法工程师写SQL时只在乎逻辑对不对不在乎跑多久。但在蚂蚁这种级别的公司一个烂SQL就会把整个数仓任务拖垮面试官很难容忍。所以在刷题时我建议要把“执行计划”和“数据倾斜”这两个概念刻在脑子里。4. 常见问题与排查技巧实录4.1 笔试中容易踩的坑我把自己和身边朋友在准备这一类笔试中的高频问题整理成了下面的速查表供大家提前避坑常见坑具体表现正确做法只答算法不答工程特征方案写得很好却没有“如何上线”每个算法方案都要配套工程方案不说明数据样本量用机器学习算法但没提数据量是否支持明确百万/亿级数据下选择不同方案的原因忽略脏数据直接假设数据是干净的写出数据质量检测和清洗逻辑时序穿越用全量数据计算特征再切分训练集严格按时间点回溯生成特征忽略特征新鲜度特征表天级更新却用于实时评分区分离线特征与在线特征SQL不做优化多表直接join、count(distinct)滥用先聚合后join用小结果集驱动大结果集没有监控和回滚只是把模型上线不监控效果设计成功率、覆盖率、AUC飘移等监控指标手写代码无注释思路只有自己能看懂注释写明每一步的关键前提和目的这里特别想强调一下“没有监控和回滚”这一点因为这是很多算法基础不错的人最容易丢分的地方。面试官问的虽然是“怎么设计模型”但心里想的其实是“你敢不敢把它放到线上”。你要是答不出“模型效果变差怎么办”“特征延迟怎么办”“如何快速回滚到上一版”他很难相信你能扛住线上事故。我每次写完方案都会再多问自己一句“这个方案如果出了线上问题第一反应是看什么指标”回答不出来就说明方案还没闭环。4.2 时间分配与临场应对心得前面提到了我的时间差点没分配好这里把实际感受分享出来。180分钟做4道综合题看似每道题45分钟但其实第一道和第二道题大概率会超时因为答题时需要边思考边写而且要把方案描述写详细。我实际的时间是第一道题50分钟第二道题55分钟第三道题40分钟第四道题只有25分钟最后一道SQL虽然写完了但明显不够从容。如果重来一次我会给自己定一个硬性时间阶梯前两道题每题不超过45分钟第三题不超过30分钟第四题至少留50分钟。原因是前两道题就算答案再精彩单题分值占比也有限而第四道题如果写不好SQL会在整张卷子上留下“这人工程能力不行”的印象这是最致命的。另外如果你遇到一道题完全没有思路我的做法是先把“最朴素的方案”写出来哪怕是暴力算法、哪怕是全部字段都做特征然后在此基础上逐步优化。这样就算得不到满分阅卷人也能看到你清晰的思维路径。最怕的是面对难题发呆20分钟最后交个白卷。笔试考的不只是你会多少更是你在有限时间内能输出多少。4.3 一个关于“特征上线”的追问式自查方法我在笔试复盘时把每道题的方案都拿来做了一个“上线自问”效果好得惊人。这个自问方法一共有五步这个特征/方案的数据源是什么由哪个团队或任务产出产出频率是多少加工逻辑是离线的还是实时的如果是实时的能否容忍秒级或分钟级延迟最终存储在哪里用什么数据结构服务查询QPS是多少是否会成为瓶颈如果线上特征缺失、延迟、值异常用什么手段兜底报警阈值是多少模型或规则上线后如何评估收益用什么指标衡量能拆分出多少个分桶做AB实验每次写方案时就对着这五步检查如果中间任何一步答不出来就立即补上。这种方式不仅笔试能用放在真实工作里做技术方案评审也一样好用。5. 备考路线与实战建议5.1 从工程视角重新梳理数据挖掘知识如果你准备时间比较充裕我建议不要一上来就刷机器学习题库。先用一周时间尝试自己独立完成一条完整的数据挖掘工程链路用Python爬一份公开数据集比如电商购买记录从数据清洗、特征工程、模型训练、模型部署、性能监控到AB实验一整个流程全部自己手写一遍。这个过程里你会遇到至少十个“文档里不会写”的问题比如模型上线后请求响应太慢、特征服务和模型服务之间数据格式不一致、离线训练AUC高但在线效果差等。解决完这些问题你对数据挖掘岗位的理解会瞬间超过只刷题的人。我当时备考前自己用一份公开的信用卡欺诈数据写了一个完整的异常检测特征服务用Flask封装了特征接口和模型预测接口再用Docker部署到本地K8s里压测了1000QPS。虽然代码粗糙但让我真正理解了“模型上线”和“训练出好模型”之间的鸿沟。到了笔试时涉及在线特征服务的题我根本不需要死记硬背直接就能写出方案。5.2 每道题的答题模板根据这次笔试经验我总结了一种适合工程数据挖掘岗的答题模板用起来很顺手。拿到任何一道方案题都按下面五段去答业务目标与评价指标先用两三句话说清楚要解决什么问题用什么指标衡量好坏。如果是风控是precision重要还是recall重要在不同的业务状态下权重是否不同数据理解与质量剖析把手上有的字段、数据量、脏数据风险点一一列出说明哪些字段可直接使用哪些需要加工哪些需要外部数据补全。方案选型及理由给出一个主导方案再加上一两个备选方案。明确说明为什么选择A而不是B最好引入一些对比表格或复杂度分析。工程链路设计从数据源、离线加工、在线访问、存储、降级、监控六个环节描述特征或模型如何从开发环境走向生产环境。风险与迭代计划提出上线后的潜在风险和失败场景说明如何监控以及如果效果不好如何快速迭代。这套模板是我在笔试现场临时摸索出来的做完几道题后发现答题速度明显提升。因为有了结构你的思路不会乱而且阅卷者在短时间里就能看到你的逻辑层次哪怕个别细节不完美整体印象分也不会低。5.3 需要掌握的SQL和数据仓库基本知识蚂蚁这种体量的公司数据挖掘工程师每天要面对的海量数据高度依赖数据仓库和分布式计算所以SQL水平直接决定了你的工程下限。我建议重点练习下面这几类SQL场景窗口函数row_number、rank、lag、lead在去重、会话划分、时间窗口统计里的应用。聚合优化先聚合再join尽量用count(distinct)的替代方案比如先用group by 去重再count。数据倾斜处理大key加随机前缀打散两阶段聚合。分区裁剪与谓词下推过滤条件下推到数据源端减少扫描数据量。时间函数与日期维度表日期序列补齐、同比环比计算、自然周/自然月对齐。这些内容看起来和数据挖掘关系不大但在笔试里往往会以“隐形的门槛”出现。SQL题答不好算法题答得再漂亮整体评价也会掉一个档次。我当时在第四道题就是因为清楚这些优化点即使时间只剩25分钟也能拿出一个相对完善的答案。5.4 面后复盘笔试真正想筛选什么笔试结束后我花了一整天复盘把每道题对应的能力点重新梳理了一遍最后得出一个共识这类笔试真正在筛选的不是“谁机器学习懂得多”而是“谁能在真实复杂的业务数据环境中稳定产出有效结果”。你有多少模型竞赛的top名次、读过多少篇论文在笔试中作用远不如你能否把一个脏乱差的源表清洗成可用特征、能否把一个模型方案变成带降级和监控的完整服务、能否在有限时间里权衡取舍。这种能力没有捷径只能在真实的项目中练。如果你现在还没进大厂建议从自己手头的小项目开始不要只停留在“用sklearn跑个模型拿个准确率”的阶段而是给自己加码数据有缺失怎么办数据量大了怎么处理模型怎么给到其他同学调用效果下降怎么发现这些真实问题锤炼出来的技能值钱得多。5.5 给下一届候选人的几点额外提醒考前一定要亲自用大数据量的表跑一遍SQL练出“数据量感”。同样是join几百行和几亿行的执行计划完全不同。手写方案时图不一定非要多好看但文字流程要清楚。我在笔试里画流程图都是ASCII字符每个箭头和判断分支都写清楚。别把简历里写的项目当摆设。笔试里遇到“什么场景下特征如何设计”时我最先想到的就是简历项目里踩过的坑真实经历比看十篇技术博客都好用。英语好不是必须但一些技术名词最好知道中英文对照比如半连接、数据漂移、热key这样阅读材料时反应更快。整场笔试做下来我最深的体会就是这个地方不缺会做模型的人缺的是能把模型做成稳定服务的人。所以无论你擅长的是机器学习算法还是数据分析面这个岗位时请把“工程”两个字刻在心里所有方案都按“设计-落地-上线-监控-迭代”的闭环来写角度对了想过笔试就成功了一大半。
返回列表