# 相关性检索优化说明(当前实现) ## 1. 文档目标 本文描述当前线上代码的文本检索策略,重点覆盖: - 多语言检索路由(`detector` / `translator` / `indexed` 的关系) - 统一文本召回表达式(无布尔 AST 分支) - 翻译缺失时的兜底策略 - 典型场景下实际生成的 ES 查询结构 > 说明:向量召回(KNN)是另一维度,本篇仅简要提及,不展开。 ## 2. 核心流程 查询链路(文本相关): 1. `QueryParser.parse()` 输出 `detected_language`、`query_text_by_lang`、`search_langs`、`index_languages`、`source_in_index_languages`。 2. `ESQueryBuilder._build_advanced_text_query()` 按 `search_langs` 动态拼接 `title/brief/description/vendor/category_*` 的 `.{lang}` 字段,叠加 shared 字段(`tags`、`option*_values`)。 3. `build_query()` 统一走文本策略,不再有布尔 AST 枝路。 ## 3. 能力矩阵(Detector / Translator / Indexed) 三类能力的职责边界: - **Detector**:识别 query 源语言(`detected_language`) - **Indexed**:租户可检索语言集合(`tenant_config.*.index_languages`) - **Translator**:源语言到目标语言的可翻译能力及实时成功率 ### 3.1 决策规则 1. 若 `detected_language in index_languages`: 源语言字段做主召回;其他语言走翻译补召回(低权重)。 2. 若 `detected_language not in index_languages`: 翻译到 `index_languages` 是主路径;源语言字段仅作弱召回。 3. 若第 2 步翻译部分失败或全部失败: 对缺失翻译的 `index_languages` 字段,追加“原文低权重兜底”子句,避免完全丢失这些语种索引面的召回机会。 ### 3.2 翻译等待策略 `QueryParser.parse()` 中: - 当源语种不在 `index_languages`:使用 `translate_multi_async(...)` 并等待 futures 收敛 - 当源语种在 `index_languages`:使用 `translate_multi(..., async_mode=True)`,优先缓存命中,未命中可后台补齐 这保证了“必须翻译才能检索”的场景不会直接空跑。 ## 4. 统一文本召回表达式 每个语言子句的基础形态: ```json { "multi_match": { "_name": "base_query|base_query_trans_xx|fallback_original_query_xx", "query": "", "fields": ["title.xx^3.0", "brief.xx^1.5", "...", "tags", "option1_values^0.5", "..."], "minimum_should_match": "75%", "tie_breaker": 0.9, "boost": "<按策略决定,可省略>" } } ``` 最终按 `bool.should` 组合,`minimum_should_match: 1`。 ## 5. 关键配置项(文本策略) 位于 `config/config.yaml -> query_config.text_query_strategy`: - `base_minimum_should_match` - `translation_minimum_should_match` - `translation_boost` - `translation_boost_when_source_missing` - `source_boost_when_missing` - `original_query_fallback_boost_when_translation_missing`(新增) - `keywords_boost` - `enable_phrase_query` - `tie_breaker_base_query` - `tie_breaker_keywords` 新增项说明: - `original_query_fallback_boost_when_translation_missing`: 当源语种不在索引语言且翻译缺失时,原文打到缺失目标语字段的低权重系数,默认 `0.2`。 ## 6. 典型场景与实际 DSL 以下示例来自当前 `ESQueryBuilder` 生成结果(已按当前代码验证)。 ### 场景 A:源语种已在索引语言中,且翻译成功 - `detected_language=de` - `index_languages=[de,en]` - `query_text_by_lang={de:"herren schuhe", en:"men shoes"}` 策略结果: - `base_query`:德语字段,正常权重 - `base_query_trans_en`:英语字段,`boost=translation_boost`(默认 0.4) ### 场景 B:源语种不在索引语言中,部分翻译缺失 - `detected_language=de` - `index_languages=[en,zh]` - 只翻译出 `en`,`zh` 失败 策略结果: - `base_query`(德语字段):`boost=source_boost_when_missing`(默认 0.6) - `base_query_trans_en`(英文字段):`boost=translation_boost_when_source_missing`(默认 1.0) - `fallback_original_query_zh`(中文字段):原文低权重兜底(默认 0.2) ### 场景 C:源语种不在索引语言中,翻译全部失败 - `detected_language=de` - `index_languages=[en,zh]` - `query_text_by_lang` 仅有 `de` 策略结果: - `base_query`(德语字段,低权重) - `fallback_original_query_en`(英文字段原文兜底) - `fallback_original_query_zh`(中文字段原文兜底) 这能避免“只有源语种字段查询,且该语种字段在商家索引中稀疏/为空”导致的弱召回问题。 ## 7. QueryParser 与 ESBuilder 的职责分工 - `QueryParser` 负责“语言计划”与“可用文本”: - `search_langs` - `query_text_by_lang` - `source_in_index_languages` - `index_languages` - `ESQueryBuilder` 负责“表达式展开”: - 动态字段组装 - 子句权重分配 - 翻译缺失兜底子句拼接 这种分层让策略调优主要落在配置和 Builder,不破坏 Parser 的职责边界。 ## 8. 兼容与注意事项 1. 当前文本主链路已移除布尔 AST 分支。 2. 文档中的旧描述(如 `operator: AND` 固定开启)不再适用,当前实现未强制设置该参数。 3. `HanLP` 为可选依赖;不可用时退化到轻量分词,不影响主链路可用性。 4. 若后续扩展到更多语种,请确保: - mapping 中存在对应 `.` 字段 - `index_languages` 配置在支持列表内 - 翻译 provider 对目标语种可用 ## 9. 建议测试清单 建议在 `tests/` 增加文本策略用例: 1. 源语种在索引语言,翻译命中缓存 2. 源语种不在索引语言,翻译部分失败(验证 fallback 子句) 3. 源语种不在索引语言,翻译全部失败(验证多目标 fallback) 4. 自定义 `original_query_fallback_boost_when_translation_missing` 生效 5. 非 `zh/en` 语种字段动态拼接(如 `de/fr/es`)