2435 字
约 8 分钟
18
S20-A21 · 查询扩展:同义词会把"准"换成"多"

一个知识库的搜索加了同义词表:"报销 → 费用/报账/核销"。上线后召回率涨了 12%,而"搜报销却返回一堆不相关内容"的投诉也涨了——因为"核销"在系统里另有一套流程(券核销),与"费用报销"完全不同。

查询扩展是"用精确性换召回"的经典手段。而它的边界在于:同义词表是按"词"建的,而用户要的是"概念"——词与概念之间并不一一对应。


1. 三种扩展方式

方式 效果
同义词(严格同义) 召回↑、精确↓(小)
近义/相关词 召回↑↑、精确↓↓
查询改写(模型) 召回↑、可能失真

第二项的风险最大:"相关"是一个很宽的关系第二项的"扩张性"体现在"一个词能带出一串":"报销"→"核销"→"券"→"优惠券",于是"两步之后就完全无关"——而表里只记了一步。
,"报销"与"核销"在字典意义上不是同义,只在某些场景相关。

第三项的"另一种失真"是"改写会丢掉用户说的条件":把"2024 年的报销标准"简化成"报销标准",于是"版本混在一起"——而它看起来是"更好的查询"。
第三项的失真在于"改写会补全用户没说的条件"(如加年份、加地区),于是检索到不该检索的东西。

2. 同义词的三种"强度"

强度 例子 用法
完全等价 手机 / 移动电话 可双向扩展
上下位 发票 / 增值税专用发票 单向(下位→上位)
相关 报销 / 核销 谨慎,需限定场景

第二项的方向很重要:"搜增值税专用发票"时扩展到"发票"是合理的(上位能覆盖),而反过来会让结果变宽。

第三项在"有歧义的领域"里最危险:"核销"在两个业务里含义不同,扩展后把两个业务的文档混在一起。第三项还有个"组织"层面的原因:两个业务各自建的词表,合并时只看到"同义词"的字面——而它们在各自语境里都对。

3. 双向 vs 单向扩展

方向 风险
双向 污染(A→B 与 B→A 都扩)
单向(严格→宽泛) 可控
只在"零结果"时扩展 最保守

第三项的"实现"很轻:一次判断(结果数 < 3),加上"第二次查询"。而它带来的收益是"精确查询零污染"——这正是扩展最容易被诟病的地方。
第三项是"性价比最高"的策略:先按原文检索,只有在"结果为空或极少"时才用扩展——于是"精确查询不被污染",而"表达不匹配"仍被救回。

// 三段式检索(保守扩展)
1 原文检索:命中 ≥ 3 条 → 直接返回(不扩展)
2 扩展检索:命中 < 3 条 → 加同义词再查一次
3 合并:原文结果优先,扩展结果作为补充(标注"相关")
// 收益:精确查询零污染;零结果仍有救

"扩展强度"可以分层开关,于是"同一个词表"能支持两种体验:

// 分层扩展(同一份词表,两种模式)
search:
  expansion:
    mode: on_zero_result        # 默认:只在零结果时扩展
    strict_only: true           # 只用"完全等价"类
  modes:
    help_center: { strict_only: false }   # 帮助中心:可用近义词(召回优先)
    knowledge_base: { strict_only: true } # 知识库:只用严格同义(精确优先)
// 收益:一份表、两套策略,不必维护两份

4. 同义词表怎么维护

来源 质量
业务方提供 高(但少)
从零结果日志里挖 高(真实需求)
从点击日志里挖 中(有噪声)
通用词典 低(不贴合业务)

第二项最实用:**"用户搜了 X 没结果,然后改搜 Y 得到了结果"**第二项的"噪声"来自"Y 只是另一个说法":用户改搜 Y 可能是因为"Y 更短/更常见",而不代表"Y 与 X 同义"。所以候选要人工确认。
——这就是一条"X 应当扩展到 Y"的证据,而它是从真实行为来的。

第四项的"判据"是"这对词在你们的语料里是否指向同一批文档":指向同一批,才算同义;指向不同批,扩展就是污染。
第四项的问题在"领域差异":通用词典里"核销"就是"报销"的近义,而在你们的系统里它们是两个流程。

-- 从零结果日志里挖同义词(X 零结果 → Y 有结果,60 秒内)
SELECT z.q AS zero_q, n.q AS next_q, COUNT(*) c
FROM search_log z
JOIN search_log n ON n.user_id = z.user_id AND n.ts BETWEEN z.ts AND z.ts + 60
WHERE z.result_count = 0 AND n.result_count > 0
GROUP BY 1,2 ORDER BY c DESC LIMIT 50;
-- 输出即"候选同义词对",需人工确认(因为 Y 可能只是"另一个说法"而非同义)

5. 扩展的"代价"怎么衡量

指标 含义
召回率(扩展后) 收益
前 10 条的"无关比例" 代价
首条点击率 净效果
零结果率 最终目标

第三项最真实:如果"扩展后首条点击率下降",说明用户被噪声干扰了第三项的"分母"要注意:合并后的结果集变了,点击率的可比性下降。所以更稳的做法是"只看"原文查询的那部分用户"的表现"(分群对比)。
——而召回率的提升没有价值。

所以"要不要加同义词"应当看"首条点击率与零结果率"这对指标,而不是单看召回。

"扩展是否有效"要做 A/B,而不是"上线后看整体指标"——因为"整体指标"会被"查询分布变化"污染:

// A/B 设计(按 uid 分流,两组都可扩展/不可扩展)
A 组(50% 流量):不扩展
B 组(50% 流量):零结果时扩展
比:零结果率、首条点击率、平均结果数
// 判据:B 组"零结果率"下降且"首条点击率"不下降 → 值得上

6. 排错:五种"扩展带来的问题"

现象 成因 处理方向
结果变多但更差 近义词扩得太宽 只保留严格同义
跨业务混在一起 同义词跨领域 加"业务域"限定
精确查询被污染 无条件扩展 改"零结果时扩展"
维护不动 表太大 只维护高频对
零结果率没降 扩展词不在语料里 补内容而非加词

第五项的"识别"是"扩展后仍然零结果":这说明"语料缺内容",而不是"词不匹配"——而修法完全不同(补文档 vs 加词表)。
第五项是"方向错误":如果语料里根本没有这个概念,扩展同义词也不会命中——此时该"补文档",而不是"加词表"。

最后一个"代际"考虑:词表是"静态补丁",而向量检索是"动态覆盖"。如果已有向量检索,同义词表主要用来"补向量也搞不定的缩写与简称"(如"公积金"→"住房公积金")。

// 三种手段的分工(不是替代)
同义词表:缩写、简称、历史叫法(静态、可控、零延迟)
向量检索:表述完全不同但语义相同(动态、需算力)
查询改写:多轮对话里的省略补全(需模型)

7. 边界:什么情况不必扩展

场景 为什么 做法
语料术语统一(内部规范) 用户也用同一术语 不扩展
精确检索(编号、错误码) 扩展会引入噪声 不扩展
已有向量检索兜底 语义匹配已覆盖 不扩展
查询量大但零结果少 收益有限 不扩展

判断口径一句话:"用户的说法"与"语料的说法"是否经常不一致。最后一条与"成本"有关的边界:词表的维护成本随"业务域数量"增长。所以"多业务共用一个词表"通常比"每域一张小表"更难维护——而后者还能避免跨域污染。
经常(口语 vs 制度术语),扩展必要;一致(都用同一套术语),扩展只是引入噪声。


8. 自测

  1. 三种扩展方式里,哪一种风险最大?为什么"相关"是一个很宽的关系?
  2. 同义词的三种强度里,哪一种"方向"最重要?举一个只能单向扩展的例子。
  3. 为什么"只在零结果时扩展"性价比最高?它保护了什么?
  4. "从零结果日志里挖同义词"为什么比通用词典可靠?
  5. 为什么"只看召回率"是错的?该看哪两个指标?
  6. 判断"是否需要扩展"的那个问题是什么?
S20-A21 · 查询扩展:同义词会把"准"换成"多"
https://www.clxhxhhr.top/posts/6594/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。