2626 字
约 8 分钟
17
S20-A19 · 多语言检索:为什么中文问句搜不到英文文档

一个内部知识库既有中文文档也有英文文档,用户用中文提问"如何配置超时",而答案在一份英文的《Timeout Configuration》里。检索返回空——因为分词器按语言切词,中文问句被切成中文 token,而英文文档的索引里没有这些 token。

这个区分很重要,因为它决定了"该改哪一层":模型能翻译,但检索发生在翻译之前——如果索引里根本没有对应的 token,再强的模型也救不回来。
多语言检索的问题不在"模型不懂两种语言",而在索引与查询的切词规则不匹配。而这三种不匹配,各有不同的修法。


1. 三种不匹配

不匹配 表现
切词规则不同 中文查不到英文
词形变化 "timeout"查不到"timeouts"
同义/术语差异 "超时"vs"timeout"

第二项在英文内部也很常见:没有词干化(stemming)时,单复数与动词变形搜不到。第一项(切词规则)在中文上更极端:中文没有空格,切词器决定了"哪些字组合成词",而英文按空格切——两者无法"自然对齐"。

第三项是"跨语言"的核心:语义相同但字面完全不同,只能靠"词典/向量"解决,不能靠"匹配"。

2. 四种修法与代价

修法 效果
双语同义词表 中(覆盖已知术语)
查询改写(翻译后检索) 中高(需模型)
多字段索引(原文 + 译文) 高(离线翻译成本)
向量检索(跨语言模型) 高(成本与调优)

第一项的维护方式建议是"从零结果日志里长出来":用户搜了什么、改写成了什么,直接给出"该补哪一对"。这比让架构师拍一份术语表更符合真实用法。
第一项最便宜也很有效:把"超时 / timeout / ttl / 有效期"这类核心术语成对维护,几十对就能覆盖大部分查询。

第三项最稳:入库时把英文文档译成中文(或反之)并存两份第三项还有个"质量"问题:机器翻译会把标识符改坏(如把 READ_TIMEOUT 译成"读取超时"),于是"按标识符搜"变得困难。所以原文必须保留,译文只作为补充字段。
,检索任一份都能命中。代价是"离线翻译成本 + 双份索引"。

// 多字段索引:原文与译文各一列,检索时都查
mappings:
  properties:
    title_zh:   { type: text, analyzer: ik_max_word }
    title_en:   { type: text, analyzer: english }
    body_zh:    { type: text, analyzer: ik_max_word }
    body_en:    { type: text, analyzer: english }
// 查询时 multi_match 覆盖四个字段,按分数合并

3. 查询改写:最实用的折中

做法 说明
规则改写(术语表) 无需模型,延迟为零
模型翻译再检索 质量高,多一次调用
双语并行检索 两个查询各查一半,合并

第三项在"不确定语言"时最稳:同一问题同时用中英查询各跑一次,把结果合并去重。代价是双倍检索开销,但召回提升明显。

第二项的关键是"翻译要保留术语":模型可能把"TTL"译成"生存时间",而库里写的是 "TTL"——于是翻译反而降低了召回。

// 双语并行检索(合并去重)
const [zh, en] = await Promise.all([
  search({ q, lang: "zh" }),
  search({ q: translate(q), lang: "en" }),
]);
const merged = dedupByDocId([...zh, ...en]).sort(byScore).slice(0, 10);
// 注意:去重按 doc_id,而不是按内容(同一文档可能两路都命中)

"查询语言识别"本身也有坑:中英混排的查询("怎么设 timeout")无法被简单判定为某一种语言。所以实践上常常"不做语言判定,直接双路检索"——因为误判的代价大于多跑一次的代价。

// 三种策略的取舍
判定语言 → 只查一路:省一次检索,但混排查询会漏
总是双路 → 查两路合并:多一次开销,但不会漏
按字符占比判定(中文 > 30% → 双路):折中,实现简单
// 推荐:总是双路(或字符占比法),因为检索本身很便宜

4. 词形与大小写

处理 效果
词干化(stemming) timeouts → timeout
小写化 Timeout → timeout
同义词(synonym) 缩写与全称互相匹配
拼音/首字母 中文场景补充

第四项在中文里很实用:"chaoshi"能匹配"超时",前提是索引里存了拼音字段。第一项(词干化)在"搜代码/API 名"时反而是负担:把 OrderService 词干化后可能变成 orderserv,于是"按原名搜"失败。所以代码字段通常用 keyword 类型,不做分析。
而它的成本是"多一个字段 + 分析器"。

第二项在"标识符搜索"上是双刃:小写化让 Timeout 与 timeout 都能命中,但让"大小写敏感"的键名搜索失真。所以"代码/配置键搜索"通常需要"区分大小写的字段"。

5. 混合语言的文档

现象 原因
中文文档里夹英文术语 分词器可能把术语切碎
英文文档里有中文注释 英文分析器丢掉中文
表格/代码块内文本 未参与索引或切分异常

第一项的修法是"多字段 + 多分析器":同一字段用两种分析器各建一份索引,查询时都试。

第三项(表格/代码块)在实际语料里占比不小:切分时若把代码块当普通文本,标识符会被切碎,于是"按函数名搜"命中率极低。
第二项要检查"分析器是否会丢弃非 ASCII"——某些英文分析器会把中文当作分隔符丢掉,于是"中英混排"文档的中文部分完全搜不到。

// 中英混排的三种索引策略
1 单一 ik_max_word(能切中文,英文按字母序列)→ 中英都能搜,但英文词形不处理
2 双字段(zh + en)→ 召回最好,索引体积翻倍
3 统一小写 + ngram → 近似匹配强,精确性差
// 推荐:2(双字段),代价可算,行为可解释

"跨语言"还有一个"反向"问题:英文查询命中中文文档时,摘要展示是中文,而用户读不懂——于是"搜到了但没用"。所以多语言检索不只是"召回",还包括"呈现":按查询语言生成摘要,或提供原文 + 译文两段。

// 召回之后的三种呈现
1 原文 + 机器译文(推荐:可核对)
2 只给模型生成的摘要(快,但可能失真)
3 只给原文(对读不懂的用户等于没召回)

6. 排错:五种"跨语言搜不到"

现象 成因 处理方向
中文问英文文档 0 结果 切词不匹配 双语索引/翻译
单复数搜不到 无词干化 加 stemmer
缩写搜不到 无同义词 术语表
中英混排只命中一半 分析器丢字符 双字段
结果相关性差 语言权重未调 按语言分权重

第五项在"双字段"里很常见:英文命中的分数天然更高(因为英文文档更短),于是中文结果被压下去。第二项(单复数)的修法有个"语言"差异:中文没有复数变化,所以这条只影响英文语料——而它对"英文技术文档库"的召回影响很大。
解法是"按查询语言给字段加权"。

最后一个"落地顺序":先做术语表,再做双字段索引,最后才考虑向量。因为术语表的成本是"几小时",双字段是"几天",向量是"几周 + 调优"——而多数团队的实际问题在"术语表没维护",不在"缺向量检索"。

// 三步走(按投入产出)
1 术语表(50 对术语):成本小时级,覆盖多数"术语不一致"
2 双字段索引(zh + en):成本天级,覆盖"语言不同"
3 跨语言向量:成本周级,覆盖"语义相同但表述完全不同"
// 多数团队在第 2 步就已经"够用"

7. 边界:什么情况不必做多语言

场景 为什么 做法
语料单一语言 无跨语言需求 单分析器
术语表已覆盖 规则改写够用 不做双语索引
用户能用对方语言提问 无需改写 不做
数据量极小 可人工浏览 不做

最后一条与"评测"有关的边界:多语言检索必须"分语言评测"。用整体指标看,中文查询的低召回会被英文查询的高分掩盖——于是"看起来 78% 可用",而中文用户几乎搜不到东西。
判断口径一句话:"用户用的语言"与"语料的语言"是否一致。一致,单语言索引就够;不一致,就必须回答"怎么把两种语言接起来"。


8. 自测

  1. 三种不匹配里,哪一种"靠匹配永远解决不了"?为什么它只能靠词典或向量?
  2. 四种修法里,哪一种最便宜也很有效?哪一种最稳但成本最高?
  3. 为什么"模型翻译"可能降低召回?翻译时该保留什么?
  4. "双语并行检索"为什么要按 doc_id 去重,而不是按内容?
  5. 中英混排文档为什么"只命中一半"?双字段方案的代价是什么?
  6. 判断"是否需要多语言方案"的那个问题是什么?
S20-A19 · 多语言检索:为什么中文问句搜不到英文文档
https://www.clxhxhhr.top/posts/6552/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。