专业书籍精读 · ML System Design Interview · 第 4 章
Machine Learning System Design Interview · Ch 4 · Ali Aminian & Alex Xu · 2023
你在 YouTube 搜「猫跳上冰箱」,不到一秒,它从一个按十亿条计的视频库里挑出十几条给你。这一章讲的就是这件事怎么做出来:一行字,怎么变成一串按「像不像你要的」排好序的视频。
你大概以为这套系统的本事在于「看懂视频」。其实它一多半的功劳在读字——标题、简介、上传者打的标签,还有机器自动生成的字幕。真正去看画面的那条路是用来补漏的:补那些谁也没写下来的东西。
视频天然没有字可以搜。以前的办法是靠上传者自己填标题和标签,两个毛病立刻冒出来:一是填的人会瞎填,标题党、堆热门词;二是很多东西压根没人会写——你想找「红色跑车在雨里漂移」,拍的人写的可能只是「周末 vlog」。
那靠人一条条看过去打标签呢?光 YouTube 每分钟就有数百小时新视频涌进来,几百个人不吃不睡地盯着看,也只够追平当天的上传量——更别提「该打哪些标签」这件事本身就没有一份写得完的清单。
一句话:两条路一起找,最后合起来排队。
它们擅长的地方正好岔开。读字那条对专有名词、型号、人名特别准,但只找得到「被写下来的」;看画面那条能捞出没人写过的内容,可它也会犯「长得像就当成是」的错——把另一只橘猫跳沙发的视频端给你。所以正经系统从来不二选一,都是两条一起跑,让彼此补漏。
把全库每条视频都提前换算成坐标、存起来,是一笔实打实的账;哪天模型升级了,这十亿条全得重算一遍、索引重建一次,那是按周按月计的工程。
搜视频不靠「看懂视频」,靠的是两条各有各的瞎点的路一起找——一条查字面、一条比「近不近」——再用一道越收越窄的漏斗,把它们交上来的候选慢慢挑成最后那十几条。
想进到具体机制、记号和示意图? → 切到精读版
这一章表面是「做一个视频搜索」,内核是一道跨模态检索题:用户给的是文字,库里躺的是画面。书给的答案不是训一个更大的模型去「理解视频」,而是把系统劈成两条互不依赖的检索路——文本元数据走传统倒排索引、视觉内容走表示学习加近似最近邻——再用一个多级漏斗把两路候选收敛成一个可排序的相关性分。难点从来不在模型,在评估口径与线上线下的分工。
本章是《ML 系统设计面试》Part II 十道真题的第 3 道。上承 Ch2 视觉搜索——那里查询和物料都是图,这里查询是文字、物料是视频,既跨了模态又多了时间维度;下启 Ch5 有害内容检测,把「多路信号怎么融合」继续往下推。现实对应任何「用文字找非文字内容」的场景:视频平台站内搜索、素材库、企业知识库、多模态 RAG 的检索层。
搜索引擎能工作的前提是被搜的东西身上有字。网页有正文,商品有标题和参数,视频什么都没有——只有一串像素和一条音轨。
最朴素的解法是让上传者自己填元数据,然后照网页搜索那一套做。这条路能跑,但漏掉两大块:
补人工标注也不成立:YouTube 侧长期公开引用的上传速度是每分钟数百小时新视频,就算一个人 1 倍速看完立刻打标,也要几百人同时看才追得平当天增量,何况「该打哪些标签」本身就没有封闭集合。
所以这一章真正要回答的是:怎么让「画面里有什么」也变成可检索的,同时不把已经很好用的词面检索扔掉。
书先把问题翻译成 ML 任务:输入一段查询文本,输出一个按相关性排序的视频列表——这是排序问题而非分类问题,没有「标准答案集」,只有相对顺序。真正定调的是下一个决定:两条检索路并行。
为什么不合成一路?因为两者的失败模式正好互补:词面检索会漏掉「没写出来的内容」,向量检索则会犯「看着像就算相关」的错,在专名、型号、人名这类要精确字面匹配的查询上尤其吃亏。拆成两条独立的路还有工程红利——能分别扩容、分别灰度,一条坏了另一条还在。
一条 10 分钟、30 fps 的视频有 18000 帧;十亿条视频若逐帧过网络,任何预算都会被烧穿。所以第一步永远是抽帧:按固定间隔(比如每秒 1 帧,10 分钟就只剩 600 帧)或按镜头切换抽关键帧,再统一解码、缩放、归一化。编码器则有两条路线:
书的倾向很实际:先上 frame-level,因为十亿量级的全库编码是一笔真金白银的账;等确认时序语义确实是瓶颈,再对特定品类升级到 video-level。这是本章最典型的「成本先于精度」的判断。
两个编码器各吐一条向量,凭什么「文字的向量」和「画面的向量」能直接比?靠训练时强行对齐。
训练数据是〈查询文本, 视频〉的配对,主要来自搜索日志——用户搜了这句话、点开并看完了这条视频,就记一条正样本。负样本几乎不用额外标注:同批次里的其他视频就是负样本,它们恰好与这句查询相关的概率极低。
目标函数用对比损失:让配对那一对的相似度 sim(q, v)(通常就是两条向量的点积)尽量高、让这句查询与批内其他视频的相似度尽量低。说人话:把「这句话该配哪段画面」做成一道从一批候选里挑出正确那个的选择题,反复考,逼两个编码器把该配对的东西摆到一起。
这套结构就是双塔:两座塔互不看对方,只在最后用一次点积相遇。它看起来是个限制——模型没机会做文字与画面的细粒度交互——却换来了本章最关键的工程性质:视频侧可以整个离线算完。
线上一次查询走四段(图 1):查询理解做纠错与意图判断,顺手把查询编码成向量;候选生成两路并行;排序对剩下的几百条跑重模型,可做查询与视频特征的交互,并加上用户画像、视频质量、新鲜度;重排序承接业务规则——过滤违规、同频道去重、地区限制、多样性。
为什么召回必须用 ANN 而不是精确检索?十亿条向量逐个算点积不可能在毫秒内完成;ANN 靠量化与分层索引把它压到毫秒级,代价是偶尔漏掉真正最近的那几条。召回阶段容得下这种错——它本来就只负责「别漏太多」,精度由后两级兜底。
双塔的价值在这里兑现:视频向量离线批量算好、灌进索引,线上只给查询算一次向量。全库编码一次可能占掉 GPU 集群几天,但摊到每次查询上接近于零。反过来说,换模型就意味着全库重算加索引重建——这是这套架构最大的一笔隐性成本,也是书里着墨最少、面试里最值得主动提的一点。
离线用 precision@k、recall@k、MRR、mAP,线上看点击率、完播率、总观看时长——各自在量什么、何时该用,见下一节的表 3。这里只留最该记住的一句:离线涨、线上不涨是常态。原因不玄:离线集合采自历史日志,天然只包含「当时被展示过的视频」,而新模型想推的那些从未被展示过的好视频,在离线集合里连出现的机会都没有。
表 1 · 两条检索路:覆盖什么、在哪失手
| 文本路 · 倒排索引 | 视觉路 · 向量 + ANN | |
|---|---|---|
| 信号来源 | 标题、简介、标签、ASR 字幕 | 抽帧后的画面内容 |
| 要不要 ML | 不要,成熟词面打分即可 | 要,两个编码器 + 全库编码 |
| 最擅长 | 专名、型号、人名、精确短语 | 没人写下来的画面内容 |
| 典型失手 | 标题党、跨语言、画面有而标题没写 | 「看着像就算相关」;训练分布外的品类近得毫无道理 |
| 更新成本 | 改元数据即时生效 | 换模型要全库重算 + 索引重建 |
| 该压哪条 | 含明确实体的查询、导航类查询 | 描述性查询、长尾语义查询 |
表 2 · 视频编码器选型
| frame-level 帧级 | video-level 视频级 | |
|---|---|---|
| 做法 | 抽帧 → 每帧过 ViT → 池化成一条 | 整段进 3D 卷积 / 时序 Transformer |
| 抓得住 | 物体、场景、画风 | 还能抓住动作与帧间变化 |
| 成本 | 低,可复用现成图文预训练权重 | 贵一个量级,算力与显存都吃紧 |
| 致命短板 | 时序丢失,正放倒放几乎等价 | 十亿量级全库编码的账算不过来 |
| 该选谁 | 默认起点 | 确认动作语义是瓶颈后,对特定品类升级 |
表 3 · 指标怎么挑(离线四个 + 线上三个)
| 指标 | 在量什么 | 什么时候用它 / 代价 |
|---|---|---|
precision@k | 前 k 条里有几条相关 | 看第一屏体验;k 不写清就不可比 |
recall@k | 相关的里被前 k 条捞回多少 | 评召回阶段;全量相关集不可知,只能靠小标注集近似 |
MRR | 第一条正确结果的位次倒数 | 只有唯一答案的导航型查询;多答案场景会失真 |
mAP | 综合各位次的精确率 | 二元相关下的整体排序质量;分级相关则不适用 |
| 点击率 CTR | 结果被点开的比例 | 最灵敏,但会被标题党和封面图带偏 |
| 完播率 | 点开后看完的比例 | 抵消标题党;对长视频天然偏低 |
| 总观看时长 | 搜索带来的总时长 | 最贴近业务,但归因链最长、方差最大 |
双塔 + 对比学习 + ANN 这套三件套,今天已经是工业界「用文字找非文字」的默认骨架:电商以文搜图、素材库检索、多模态 RAG 的检索层,结构都和这一章一模一样。面试里的高频追问集中在两处——为什么不做单塔交互模型(答:物料侧无法离线预算,十亿量级不可能在线逐条过模型),以及离线涨线上不涨怎么查(答:先怀疑评估集的曝光偏差,再查线上线下特征是否一致)。
precision@k 而不交代 k 取多大、相关性由谁标、查询集怎么采样,这个数根本不可比。① 一句话:视频搜索是跨模态检索——查询是文字、物料是画面;答案不是「训个更大的模型看懂视频」,而是拆成两条互补的检索路加一个多级漏斗。
② 问题本质:被搜的东西身上没有字。靠上传者填元数据会漏掉「没写下来的画面」,还会被标题党污染;人工标注在每分钟数百小时的上传量前不成立。
③ 两条路:文本路走倒排索引(标题 / 简介 / 标签 / ASR 字幕,完全不用 ML),视觉路走表示学习 + ANN;失败模式互补,所以并行而非二选一。
④ 视频编码先抽帧(10 分钟 30fps 共 18000 帧,按 1fps 只留 600 帧);帧级便宜但丢时序,视频级抓得住动作却贵一个量级——默认从帧级起步。
⑤ 对比学习把文字与画面钉进同一个空间:正样本来自搜索日志的配对,负样本用同批次其他视频,把配对的 sim(q, v) 拉高、其余压低。
⑥ 双塔的真正价值是工程性的:视频向量离线算完灌进索引,线上只算查询那一条;代价是换模型要全库重算加索引重建。
⑦ 服务四级漏斗:查询理解 → 两路候选(10³)→ 排序(10²)→ 重排序 → 结果(10);召回容得下 ANN 的近似误差,精度由后两级兜底。
⑧ 评估:离线四个指标各量不同的东西,线上看点击率、完播率、总观看时长;离线涨线上不涨是常态,首要嫌疑是评估集的曝光偏差。