跳转到内容

DSSM — 把 query 和文档各编码成 128 维向量再算余弦

是什么

DSSM(Deep Structured Semantic Model)是一种**让搜索引擎不再死抠关键词、能理解”意思”**的检索模型。日常类比:你问”附近哪家店便宜又好吃”,旧搜索只会找文档里恰好出现”便宜""好吃”的页面;DSSM 学过你点过什么之后,能把”性价比高的餐厅”也召回——尽管这页面里一个字都没重合。

它的做法说穿了一句话:

  • query 塞进一个神经网络,吐出一个 128 维向量
  • 每篇候选文档塞进结构相同但参数不同的另一个神经网络,也吐出 128 维向量
  • 两个向量做余弦相似度,越高代表”语义越接近”

这就是后来所有人嘴里说的双塔模型

为什么重要

不理解 DSSM,下面这些事讲不清楚:

  • 为什么 2024 年的 RAG(检索增强生成)能精准召回出”语义相关但词都不一样”的文档
  • 为什么淘宝、YouTube、抖音的推荐系统都在用”双塔召回”
  • 为什么 OpenAI 的 text-embedding-3、BGE、E5 这些向量模型本质上都是 DSSM 的徒孙
  • 为什么 sentence-BERT(2019)被很多人当作”句向量鼻祖”,但其实 DSSM 早 6 年就在工业上跑了

一句话:今天所有”把句子压成一个向量再比相似度”的检索系统,DSSM 是它们的祖宗

核心要点

DSSM 的关键拆成 四件事

  1. 双塔:query 和 document 走两条神经网络,最后都映射到同一个 128 维空间。塔之间不共享参数——因为查询和被查的文档语言风格不一样(query 短而碎,doc 长而正式)。

  2. letter trigram(字母三元组哈希):把 web 拆成 #we / web / eb#(# 是边界符)。50 万个英文单词的输入维度被压到约 3 万维 trigram,并且没见过的新词也能拆——天然解决 OOV(未登录词)。

  3. 点击数据当监督:用户在必应搜了 query 后点过的 doc 是正样本,没点的(或随机抽的)是负样本。损失函数让正样本对的余弦更大、负样本对更小(pairwise softmax)。没人手工标注,全靠用户用脚投票

  4. 离线建库 + 在线查询:所有文档向量提前算好存索引,用户来了只需在线跑一次 query 塔得到 128 维向量,然后做近邻召回。所以双塔必须独立——共享参数就没法离线预计算。

实践案例

案例 1:query 和 doc 词都不一样也能匹配

用户搜:how to fix slow laptop

数据库里有篇文档标题:speeding up an aging notebook computer

字面零重合,BM25 打不出分。但 DSSM 训练数据里见过有人搜类似 query 后点过类似 doc,两个向量在 128 维空间里就被拉近了。意思接近的东西在向量空间里就近——这是核心收益。

案例 2:letter trigram 的妙处

输入 boy 拆成:

#bo, boy, oy#

输入 boys 拆成:

#bo, boy, oys, ys#

前两个 trigram 完全一样——所以 boy / boys 的输入向量天然就接近,不需要任何”词形归一化”。新词 cryptobro 来了?拆成 #cr, cry, ryp, ypt, pto, tob, obr, bro, ro# 一样能编码。这套技巧今天看仍然惊艳,是 word2vec 同期的另一种思路

案例 3:模型结构小到吓人

维度
输入(letter trigram)30,000
隐层 1(tanh)300
隐层 2(tanh)300
输出(语义向量)128

总共三层全连接。按 2026 年标准是个玩具,但当年 NDCG@1 比 BM25 高约 4.3%,比 LSA 等无监督方法高 4-5%。重点不是模型多大,是第一次把”点击日志 + 神经网络 + 双塔”组合起来打通了端到端

踩过的坑

  1. 以为 DSSM 是 transformer:不是。它就是个三层 MLP,token 级靠 letter trigram 切分,没有 self-attention,也没有词序。“deep” 在 2013 年的语境是”超过两层”。

  2. 以为可以替代 BM25:工业上从来不是。线上一般是 DSSM 召回 + 大模型精排 + BM25 兜底的混合。BM25 对完全字面匹配仍然最稳,DSSM 补语义那部分。

  3. 以为单向量够用:把整个文档压成 128 维,长文档信息严重丢失。这是后来 ColBERT 改成”每个 token 一个向量”的根本原因(叫 late interaction)。

  4. letter trigram 中文用不了:中文没空格,trigram 概念失效。后续 CNN-DSSM / LSTM-DSSM 改成字 n-gram 或 LSTM 编码才解决。

  5. 点击数据的曝光偏差:用户只能点搜索结果里已经被排上前的文档,没排上前的根本没机会被点。直接用点击当监督会强化”现有排序”,需要 IPS(逆倾向加权)等技术校正。

适用 vs 不适用场景

适用

  • 大规模检索召回(百万 - 十亿级文档),需要离线预计算 + 在线 ANN
  • 推荐系统的双塔召回(user 塔 + item 塔)
  • 有大量隐式反馈(点击 / 购买 / 观看)的场景
  • 现代 RAG 系统的 embedding 模型选型起点

不适用

  • 文档很长且需要保留细粒度信息 → 用 ColBERT 这种多向量方案
  • 完全冷启动场景(没历史点击)→ 退回 BM25 或用预训练语言模型零样本
  • 需要词序和长距离依赖 → 至少要换成 LSTM-DSSM 或 BERT 双塔
  • 跨语言检索 → letter trigram 不通用,要重新设计输入端

谱系小故事(可跳过)

  • 1993:Bromley 等人提出 Siamese network 用来验证签名笔迹是否一致——双塔思想的起点
  • 1990s:LSA / PLSA 用矩阵分解做无监督语义检索,但不能用上点击数据
  • 2013:word2vec 把压成稠密向量;同年 DSSM 把句子/查询压成稠密向量,方向上是兄弟工作
  • 2014:CNN-DSSM 把 MLP 换成 CNN,捕捉局部 n-gram
  • 2016:LSTM-DSSM 处理长序列
  • 2019:sentence-BERT 把双塔思想搬到 BERT 上,名声大噪
  • 2020:DPR(Dense Passage Retrieval)+ BERT + 难负样本采样,开启 RAG 检索时代
  • 2020:ColBERT 抛弃单向量瓶颈,改成 token 级多向量

DSSM 的架构骨架(双塔 + 余弦 + 弱监督)13 年没怎么变,只是把每个组件换成了更强的版本。

几个常见困惑

Q:为什么用 cosine 而不是欧氏距离?

cosine 只看方向不看长度,对向量长度的微小波动免疫。语义检索关心”方向是否一致”(意思是否相似),不关心”向量多长”。配合 softmax 训练时 cosine 也更数值稳定。

Q:query 塔和 doc 塔为什么不能共享参数?

如果共享参数,query 塔输出就需要和 doc 塔输出对齐——那 doc 向量就必须等用户输入 query 后才能算。离线建库 + 在线召回的工程红利彻底没了。所以双塔必须独立——这是工程逻辑,不是模型逻辑。

Q:sentence-BERT 出来后 DSSM 没被淘汰吗?

工业上没。DSSM 系(淘宝、YouTube)一直在迭代,因为:(1)BERT 双塔推理成本高,对长尾查询不划算;(2)DSSM 训练用点击,与业务目标天然对齐;(3)双塔架构本身就是 DSSM,sentence-BERT 只是换了塔的内部实现。

学到什么

  1. 双塔的本质是”离线 + 在线”分离——这是它能做到亿级检索的工程核心。共享参数的单塔模型做不到这点。
  2. 弱监督 >> 无监督:点击数据虽然有偏差,但比 LSA 那种纯字面共现强得多。“用用户的脚投票”是 deep learning + 工业系统的天作之合。
  3. 架构复用比模型大小重要:DSSM 的三层 MLP 在今天看是玩具,但架构骨架被沿用到所有现代向量检索系统。
  4. 每一层都能换:输入换 trigram → CNN → LSTM → BERT;监督换点击 → 难负样本 → 蒸馏。骨架不变,配件升级——这是 DSSM 最值钱的设计。
  5. **2013 年三个面向稠密表示的工作(word2vec、DSSM、GloVe)**几乎同时出现,不是巧合——硬件和数据同时跨过门槛,是稠密语义表示的”寒武纪”。

延伸阅读

关联

  • word2vec —— 同年提出,把压成稠密向量;DSSM 把句子压成稠密向量,互为兄弟工作
  • bert —— 2018 年的预训练语言模型;后来取代 DSSM 三层 MLP 成为新双塔
  • colbert-v2 —— DSSM 的直系后裔,把单向量瓶颈拆成 token 级多向量
  • anserini-2017 —— Lucene + BM25 工业基线,DSSM 在产线上常常和它做混合检索