想象你走进一家热闹的餐厅,对服务员说:“我要一个红的、酸的,嗯……就那个……跟鸡蛋炒的。”正常人一听就懂——番茄炒蛋。但搜索引擎不像人这么聪明,它收到的不是完整的语音,而是一串字符:“红的酸的跟鸡蛋炒的”。为了让这串字符变成后厨能做的菜,服务员(搜索引擎)得做一连串工作:先听清每个字(预处理),再断句(分词),判断你到底是想来点菜还是打听菜价(意图识别),纠正你说的错字(纠错),把“番茄”改写成“西红柿”(同义改写),最后从菜单里端出最接近的几道菜(扩展召回)。这一整套“听懂并改写你需求”的过程,就是查询理解与改写(Query Understanding & Rewriting)。本文将用这条“餐厅点餐”的线,带你从头到尾走一遍搜索引擎的第一道关卡,并聊聊长尾 query、模糊 query 以及效果评估这些实战话题。
学完这部分,你会理解搜索系统最前端的决策逻辑,掌握分词、纠错、改写、语义召回等 Query 处理方法,这是搜索、推荐、对话系统算法工程师和架构师的必备基本功。
目录
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
Query理解多层处理流水线 ——纠错→意图→实体→改写→召回 纠错:编辑距离修复拼写错误 意图:导航/信息/事务分类 改写:同义扩展+语义召回 原始query精确匹配优先,改写扩展补充召回
查询预处理:先替用户把话听清楚
餐厅里人声嘈杂,顾客隔着老远喊:“我要那个……红的……嗯……酸的那种!”服务员不会急着跑去厨房。她先要确认自己听到的确实是对方说的,再把“嗯、那个”这类语气词滤掉,最后才在点菜单上写下“酸汤肥牛一份”。搜索引擎收到的原始 query,就像这句含混的话,混杂着各种噪音:多余的感叹号、乱入的空格、全角半角混用、甚至 URL 编码残留(比如 %20 代表空格)。
Query 预处理是搜索引擎的第一道关卡,它的目标只有一个:在花钱做复杂分析之前,先用低成本规则把 query 洗干净。常见操作包括 URL 解码(把 %E7%BA%A2 还原成“红”)、大小写归一(iPhone → iphone)、繁简转换(“蕃茄” → “番茄”)、全半角统一(把 full 转成 full),然后做停用词过滤——“的、了、吗、呢”这类词对点菜没有营养,直接扔掉。
这里用集合差运算可以很简洁地表达“去掉停用词”这一步:
预处理就像服务员把“嗯……那个……红的……”落成一句干净的“酸汤肥牛”,做完这步,query 才敢交给后端的“厨房”做深加工。
- 原始查询集合 \mathbf{Q}表示用户输入经过解码、归一后留下的全部候选词,就像服务员记下的所有发音,还没决定哪些有用。
- 停用词表 S收集“嗯、那个、的、了”这类语气词和虚词,对理解语义没有营养,直接排除在关注范围之外。
- 过滤取差集从 \mathbf{Q} 中删掉所有属于 S 的元素,得到只保留实义词的 \mathbf{Q}',这就是后续分析的起点。
分词技术:在连续字符里划出语义边界
“那个红的酸的”连在一起时,服务员必须判断该在哪里断句:“红的 / 酸的”是两个属性,还是“红酸”是一种新口味?断句位置不同,理解完全不同。中文的天然难题就在这里——英文单词之间有空格,中文没有。搜索引擎收到的是连续字符串,第一步必须先分词,否则后面的意图识别、改写全部无从谈起。
主流分词技术分两派。词典分词:准备一本大词典,用正向最大匹配或逆向最大匹配把连续字符切分成词典里存在的词,速度快但遇到词典外的“未登录词”就抓瞎。统计分词:从海量语料里学习字与字共现的概率,用语言模型判断什么地方最可能成词。实际线上系统通常两者结合:词典打底,统计模型兜底。
统计分词里最朴素的一个信号是词频——某个字串在语料里出现得越多,它越像是一个“真词”:
断句位置决定理解方向,分词也一样。切错了词,后面纠错和改写都很难把意思扳回来。
- 词频计数 count(w)统计字串 w 在语料库中出现的次数,出现次数越多,说明人们越常把它当成一个整体,比如“酸汤”出现 5000 次,“酸汤肥牛”作为整体出现 30 次。
- 语料总词数 N把所有词的出现次数全部加起来,得到一个归一化的分母,让不同词频可以横向比较。
- 词频得分 Score(w)两者相除得到 0 到 1 之间的概率估计,越接近 1,说明这个字串被语言社区“约定俗成”地当作一个词的概率越高。
意图识别:判断顾客到底想干什么
顾客说“你们这有没有酸汤肥牛”——他是想直接点这道菜(交易),还是想打听“你们家做不做这道菜”(信息),甚至只是路过随口一问(导航)?服务员的应对方式完全不同。搜索引擎也一样,同一句话在不同意图下,要展示广告、结果页还是直接跳转,差别巨大。
Query 意图识别通常分三类:导航型(用户想找某个特定网站或品牌,如“淘宝官网”)、信息型(用户想获取知识,如“番茄炒蛋的做法”)、交易型(用户想完成购买或预约,如“iPhone 15 多少钱”)。实际系统中会用分类模型,输入分词结果、词性、历史点击信号等特征,输出每个意图的概率。
这个决策过程可以写成:
意图一旦判断错,就像服务员把打听当成点单,整桌的服务都会跑偏。所以意图识别通常放在分词之后、纠错改写之前,因为它决定了后续资源的配置方向。
- 特征向量 \mathbf{x}从 query 中抽取的信号,比如分词后的词序列、是否含价格词、用户点击历史等,相当于服务员观察到的“语气、表情、时间点”。
- 候选意图集合 \mathcal{Y}预先定义好的意图类别,典型是导航、信息、交易三类。
- 条件概率 P(y \mid \mathbf{x})分类模型给出的“在观察到这些特征时,意图是 y”的概率,对应服务员心里的判断:八成是想点菜,两成是打听而已。
- 取最大者 \arg\max在所有候选意图里挑概率最大的那个作为最终判断 \hat{y},就是“先按最可能的意图接待客人”。
查询纠错:把“飞牛”悄悄改回“肥牛”
顾客把“酸汤肥牛”说成“酸汤飞牛”,有经验的服务员不会当场纠正,而是在下单时默默写成“酸汤肥牛”。搜索引擎也一样——用户输入错别字太常见了,尤其是拼音输入法带来的音近字、五笔带来的形近字,比如“苹果”打成“平果”,“番茄”打成“翻茄”。
查询纠错的通用距离度量叫编辑距离(Levenshtein Distance):把一个字符串变成另一个字符串,最少需要多少次插入、删除、替换。搜索引擎会为用户的错词生成候选词(比如“飞牛” → “肥牛”),用编辑距离和语言模型对候选打分,只有高置信度的修正才会真正生效。
编辑距离的递推公式非常经典:
纠错的核心原则是“高置信度才动手”。如果用户本来打的就是一个地名人名,强行纠正反而会把对的改成错的,这就是为什么纠错模块必须搭配上下文感知和概率阈值。
- 子问题 d(i, j)表示 a 的前 i 个字符变成 b 的前 j 个字符需要的最少操作数,就像一点一点把“飞牛”挪向“肥牛”。
- 删除操作 +1a 的第 i 个字符多出来了,删掉它,代价 1 步。
- 插入操作 +1b 的第 j 个字符在 a 里没有,补上它,代价 1 步。
- 替换或保留若 a_i 与 b_j 相等则不需要额外代价(为 0),否则替换为 b_j 的代价是 1 步。[a_i ≠ b_j] 是艾弗森括号:条件真取 1,假取 0。
同义改写:换一种说法,还是同一道菜
这家店菜单写“番茄牛腩”,隔壁顾客叫它“西红柿炖牛肉”。服务员心知肚明:说法不同,指的是同一道菜。搜索引擎每天要面对海量同义表达——“笔记本电脑”和“手提电脑”,“怎么减肥”和“瘦身方法”,字面完全不同,但语义一致。不做同义改写的搜索引擎,只能靠词面重合召回,漏掉大量好结果。
同义改写有三个层次:同义词替换(用同义词词典把“番茄”换成“西红柿”)、句法改写(把“怎么做番茄炒蛋”调整为“番茄炒蛋的做法”,让结构更贴合可检索文本)、大模型(LLM)生成改写(用生成模型把口语化 query 改写成规范的书面表达)。近年来,LLM 改写成为主流方向,因为它能捕捉上下文相关的同义关系,比如“苹果”在某些 query 里指水果、在另一些 query 里指手机品牌。
无论用哪种方式改写,都必须回答一个问题:改写前后的语义有多接近?最常用的度量是向量余弦相似度:
改写不是自由发挥,而是用相似度“校准”方向,保证改写后的 query 还是原点的意思,而不是跑到隔壁去了。
- 语义向量 \mathbf{v}_q用预训练模型(如 BERT、Sentence-BERT)把原 query 编码成一个固定维度的向量,向量里凝聚了 query 的语义信息。
- 点积 \mathbf{v}_q \cdot \mathbf{v}_{q'}把两个向量的每一维相乘再求和,衡量它们在同一方向上的投影大小。
- 模长归一化除以两个向量的模长乘积,消除 query 长度差异带来的影响,让结果落在 [-1, 1]。
- 相似度得分越接近 1,表示两个向量方向越一致,改写越“忠实于原意”,可以放心用改写后的 query 去召回。
语义扩展召回:把相近的菜都端上来
“酸汤肥牛”卖完了,服务员会推荐同口味的“番茄牛腩”或者“酸汤鱼”,但绝不会端上一盘拍黄瓜。这就是扩展召回的精髓:在精准之外,把语义相近的候选也一并捞出来。搜索引擎的召回阶段同样要做这样的“推荐”——相关搜索词、同义改写词、向量召回语义相似文档,全都进入候选集,再由排序层把关。
召回策略里,精确匹配(字面完全一致或编辑距离极小的 doc)最可控,适合品牌词、型号词;向量召回(把 query 和 doc 都映射成向量,用 ANN 检索近似最近邻)泛化能力最强,适合语义相关但字面不重合的长文本。实际系统中两者必须共存,用混合打分公式融合:
混合召回就像服务员一边看菜单原话,一边凭经验联想,既不会答非所问,也不会漏掉隐藏的好菜。
- 精确匹配分 Exact(q, d)基于词面重合的得分,比如 BM25 或 Jaccard,字面一致时得分最高,用户搜"iPhone 15"就严格命中商品标题。
- 语义匹配分 Sim(q, d)向量相似度或深度语义匹配模型的得分,能捕捉“笔记本”和“手提电脑”这类同义关系。
- 融合权重 λ介于 0 和 1 之间的超参数,λ 大则偏精确、λ 小则偏语义,线上通过小流量实验来调优。
- 最终排序分两条通道加权求和,得到每个候选文档的最终得分,取 Top K 进入精排,这是“端菜”的候选名单。
长尾与评估:接住奇奇怪怪的点单,并算清满意度
总有顾客点出菜单上根本没有的菜,比如“那个红红的东西配黄黄的、酸酸的”。好服务员也能接住——她要靠经验猜出大概是“番茄炒蛋”。搜索引擎里的“奇怪点单”就是长尾 query:出现频次低、形式多样,比如“手机充电口松了怎么办”、“如何给猫剪指甲不受伤”,它们占了 Query 总量的大多数,但每个单独出现的频率极低。另一类是模糊 query:用属性、代词描述需求,比如“红红酸酸的”,需要靠上下文和知识库来猜。
处理长尾 query 有两个常用手段:一是模板挖掘,从历史日志中归纳出高频句式模板,如“如何 + 动作 + 宾语”,再套用模板改写新 query;二是LLM 改写,利用大模型的泛化能力把口语化的长尾描述改写成可检索的规范表达。但无论哪个手段,都要有科学的评估机制,否则只是自我感觉良好。
评估 Query 改写效果最常用的指标是 F1,它把“推得准不准”和“推得全不全”统一成一个数:
F1 是离线评估的“满意度调查”,但真正决定改写好坏的,还要看线上端到端验证——把改写开关放到 A/B 实验中,观察点击率、转化率等流量指标。毕竟,客人满意不满意,最终要看他下次还来不来。
- 精确率 Precision改写后召回的文档中真正相关的比例,回答的是“推的菜客人爱吃吗”。
- 召回率 Recall所有相关文档中被成功召回的占比,回答的是“客人想吃的菜端出来了几道”。
- 调和平均 F_1当精确率和召回率严重不平衡时,调和平均比算术平均更容易暴露短板,因此 F1 高才说明改写策略整体稳健。
AI 应用场景
电商搜索的 Query 语义改写
阶段:Query 理解与召回优化
解决的问题:用户搜“苹果电脑充电器”,而商品标题是“MacBook 充电器”,字面完全不匹配,传统检索会漏掉正确商品。像服务员听不懂“苹果电脑”就是"MacBook",眼睁睁放走了客人。
具体案例:某电商平台在召回前对 query 做同义改写,将“苹果电脑充电器”改写为“MacBook 充电器”加入召回,同时保留原词做精确匹配,上线后搜索点击率提升 12%,长尾 query 的成交转化率提升 8%。
智能客服对话中的 Query 改写
阶段:对话系统 Query 理解与意图识别
解决的问题:用户说“我要退了昨天买的那个红的”,“那个红的”是模糊指代,客服机器人无法直接处理。就像服务员要结合记忆判断客人说的是哪盘菜。
具体案例:智能客服系统结合对话上下文,把“那个红的”改写为明确的商品实体“订单 #20240512 红色卫衣 退款”,再触发售后流程,同时识别出交易型意图,退款办理时长缩短了 50%。
视频平台长尾 Query 召回优化
阶段:长尾 Query 分析与多路召回
解决的问题:大量低频 query 如“怎么夸朋友做饭好吃”没有历史点击数据,向量召回效果不稳定,直接导致搜索零结果。相当于客人点了一道菜单之外的菜,服务员不能只会说“没有”。
具体案例:平台用模板挖掘把“如何做 XXX”归并到教程类目,再用 LLM 将长尾 query 改写成多个子查询,分别走精确召回和向量召回,最终搜索零结果率下降 30%,长尾流量增长了 20%。
Python 演示
import re class QueryProcessor: def __init__(self): self.stop_words = {'的', '了', '吗', '呢', '啊', '是', '在', '和', '我想吃'} self.vocab = ['酸汤肥牛', '西红柿', '番茄', '炖牛肉', '牛肉', '鸡蛋', '土豆'] self.synonym_map = { '番茄': '西红柿', '土豆': '马铃薯', '鸡蛋': '蛋类' } def clean(self, query): query = query.strip().lower() query = re.sub(r'\s+', ' ', query) return query def segment(self, query): tokens = [] for word in sorted(self.vocab, key=len, reverse=True): if word in query: tokens.append(word) query = query.replace(word, ' ') remain = [w for w in query.split() if w and w not in self.stop_words] return tokens + remain def edit_distance(self, a, b): d = [[0] * (len(b) + 1) for _ in range(len(a) + 1)] for i in range(len(a) + 1): d[i][0] = i for j in range(len(b) + 1): d[0][j] = j for i in range(1, len(a) + 1): for j in range(1, len(b) + 1): cost = 0 if a[i - 1] == b[j - 1] else 1 d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost) return d[len(a)][len(b)] def correct(self, token): best = token best_dist = 2 for cand in self.vocab: dist = self.edit_distance(token, cand) if dist < best_dist: best = cand best_dist = dist return best def rewrite(self, token): return self.synonym_map.get(token, token) def run(self, query): q = self.clean(query) tokens = self.segment(q) tokens = [self.correct(t) for t in tokens] tokens = [self.rewrite(t) for t in tokens] return tokens if __name__ == '__main__': qp = QueryProcessor() for q in ['酸汤飞牛', '番茄炖牛肉']: print(q, '=>', qp.run(q))
self.stop_words = {'的', '了', '吗', ...}定义停用词表,相当于服务员要屏蔽的“语气词”,提前过滤掉没营养的字。def clean(self, query):清洗入口,去掉首尾空格、统一小写,对应查询预处理中的语义归一化。def segment(self, query):用词典做简单分词,按词长降序匹配,保证长词优先被切出来。def edit_distance(self, a, b):动态规划实现编辑距离,是拼写纠错的核心度量,对应“飞牛”到“肥牛”需要几步。cost = 0 if a[i - 1] == b[j - 1] else 1两个字符相同则替换代价为 0,否则为 1,这是编辑距离递推的关键。def rewrite(self, token):同义改写,把“番茄”替换成“西红柿”,相当于服务员明白两种说法是同一道菜。def run(self, query):串联整个流水线:清洗 → 分词 → 纠错 → 改写,一条龙完成 Query 理解。
常见误区
误区不少人认为分词切得越细,后面的语义分析就越准确,最好把每个字都单独切开,这样信息量最大。
正解分词粒度要和场景匹配。切得太细会产出大量无意义的碎片(比如“酸”“汤”“肥”“牛”四个字),反而丢失了“酸汤肥牛”这个整体概念;切得太粗又会让“番茄炒蛋”成为一个无法泛化的词。好的分词粒度以“语义完整”为导向——每个词代表一个完整含义,就像服务员断句要按“菜的叫法”切,而不是按笔画切。
为何常见:因为传统 N-gram 语言模型里,切得越细数据越稀疏的问题被误读成“信息量越大”,让人误以为细粒度一定更好。
误区用户输入只要有错别字就必须改过来,改得越多越好,否则会漏掉正确结果。
正解过度纠错会误伤专有名词、品牌名、人名和外文音译词。比如用户搜“nike“被拼成”nikee“,但”nikee“可能是一个小众潮牌名。工程上通用的做法是生成候选集 + 置信度阈值,只接受高置信度的修正(比如编辑距离为 1 且语言模型得分极高),剩下的保持原样。否则就像服务员把顾客点对的”梅菜扣肉“当成”没菜扣肉”去改,改完菜都没了。
为何常见:语文教育让我们对错别字零容忍,而且离线评测样本里往往只挑了“改对了”的案例,忽略了“误改了正确 query”的损失。
误区把一个 query 改写成十几种不同说法,肯定能召回更多结果,效果自然更好。
正解改写会引入噪声,改写后的 query 可能与用户真实意图发生偏移。比如把“苹果怎么吃”改写成“苹果手机使用技巧”,两路召回互相冲突,反而污染了候选集。正确策略是“改写不溢出”——每一条改写都要经过相似度阈值和历史点击反馈筛选,宁缺毋滥。就像一个服务员可以推荐相似菜,但不能把粤菜馆的菜单硬翻成川菜。
为何常见:因为离线评测时只盯着召回率有没有提升,忽略了精确率下降和相关结果劣化带来的线上损失。
误区有了深度学习词向量和向量召回,传统的字面精确匹配就该被淘汰,向量召回“智能”多了。
正解精确匹配对专有名词、型号、代码、长尾标识符最可靠。用户搜“RTX 4090“,向量召回可能召回一堆”高性能显卡“的泛泛内容,而精确匹配能精准命中商品页。工业界的主流是混合召回:精确匹配兜底,向量召回负责泛化,两者用权重融合——这正是”服务员既要听清菜名原话,也要会联想同类菜”的道理。
为何常见:因为向量召回在标准评测集(如 MS MARCO)上指标亮眼,让人误以为它已经在所有业务场景全面超越了字面检索。
面试题
Q1. 搜索引擎把用户输入的“搜 索”合并为“搜索”,主要属于哪种 Query 处理?
- A.结果排序阶段处理
- B.查询预处理规范化← 正确答案
- C.文档索引构建处理
- D.用户行为反馈分析
答案:B。合并多余空格、大小写转换、繁简归一都属于查询预处理里的语义归一化,相当于服务员先听清顾客的话再下单。排序、索引构建和用户行为分析都发生在 Query 理解之后,不负责清洗输入。
Q2. 词典分词的最大缺点是什么?
- A.对未登录词处理困难← 正确答案
- B.运行速度非常缓慢
- C.不依赖任何词典资源
- D.完全无法处理中文
答案:A。词典分词靠预置词典切词,遇到词典里没有的新词(品牌名、网络热词、人名)就切不准,这是它的致命短板。它运行速度快、依赖词典资源,而且恰恰是处理中文的常用方法。
Q3. “笔记本电脑”这类词若不在分词词典中,通常被称为什么?
- A.高频常用词
- B.停用功能词
- C.未登录新词← 正确答案
- D.语义同义词
答案:C。词典里没有收录、分词时无法识别的词叫“未登录词”或“新词”。停用词是要过滤的虚词,同义词是另一个概念,高频常用词与是否收录无关。
Q4. 关于查询纠错,以下哪种做法最合理?
- A.所有拼写错误都无脑纠正
- B.纠错后效果必然提升
- C.需结合上下文避免误伤← 正确答案
- D.纠错改写无关紧要
答案:C。纠错必须高置信度才动手,结合上下文判断,防止把品牌名、人名等专有名词误改。它并非越改越好,也不是无关紧要,而是要在“改对收益”和“误伤风险”之间权衡,就像服务员不能把顾客说对的菜名强行改掉。
Q5. 对 Query 做同义改写后,还必须做什么?
- A.把原词删除不再使用
- B.评估改写后的搜索效果← 正确答案
- C.将所有词都强制改写
- D.直接丢弃用户原始输入
答案:B。改写后必须做质量评估和效果验证,确认改写确实提升了召回和点击,而不是引入噪声。原词通常要保留参与精确匹配,无脑改写所有词会误伤语义,用户原始输入也不能丢弃。
Q6. 精确匹配与语义召回融合时,参数 λ 的作用是什么?
- A.控制两者权重平衡← 正确答案
- B.决定索引存储大小
- C.影响网络传输速度
- D.决定语料库的大小
答案:A。融合公式 Score = λ×Exact + (1−λ)×Sim 中,λ 控制字面匹配和语义匹配的贡献比例。它不涉及索引、传输或语料库规模,纯粹是权衡两条召回通道的权重。
Q7. 长尾 Query 的主要特征是什么?
- A.搜索频次极高频率
- B.出现频次低且形式多样← 正确答案
- C.每次搜索时间很长
- D.一定包含错误拼写
答案:B。长尾 Query 指出现频次低、表达形式丰富的查询,总量大但单个出现少。高频词属于头部,搜索时间与 Query 特征无关,拼写错误也不是长尾的必要条件。
Q8. 下列哪些环节属于 Query 理解与改写流程?
- A.查询预处理与分词← 正确答案
- B.意图识别与纠错← 正确答案
- C.索引压缩与存储
- D.同义改写与扩展召回← 正确答案
答案:ABD。预处理、分词、意图识别、纠错、同义改写、扩展召回都是 Query 理解与改写的核心环节。索引压缩与存储属于离线索引工程,与用户查询理解无关。
Q9. 关于向量召回与精确匹配,正确的说法有哪些?
- A.向量召回支持语义相似召回← 正确答案
- B.精确匹配保证字面一致性← 正确答案
- C.两者只能选择其中一个
- D.混合策略可以优势互补← 正确答案
答案:ABD。向量召回用语义向量找相似内容,能处理“番茄”和“西红柿”这类同义关系;精确匹配保证字面一致,适合型号和品牌词。两者并非二选一,工业界普遍混合使用,发挥各自优势。
Q10. 某 Query“红斑狼疮怎么治”被 LLM 改写出疑似广告意图的结果,最合理的线上处置是什么?
- A.直接上线该改写结果
- B.加安全过滤并人工抽检← 正确答案
- C.删除模型改用纯词典改写
- D.只扩充语料库不改模型
答案:B。涉及医疗等敏感领域时,LLM 改写必须加安全过滤规则,并对高风险改写结果进行人工抽检,防止诱导广告或错误信息上线。直接上线风险极高;删掉模型是因噎废食;只扩语料不改策略解决不了生成侧的意图偏移。