15 Apr, 2026
2 commits
-
修改内容 1. **新增配置项** (`config/config.yaml`) - `exact_knn_rescore_enabled`: 是否开启精确向量重打分,默认 true - `exact_knn_rescore_window`: 重打分窗口大小,默认 160(与 rerank_window 解耦,可独立配置) 2. **ES 查询层改造** (`search/searcher.py`) - 在第一次 ES 搜索中,根据配置为 window_size 内的文档注入 rescore 阶段 - rescore_query 中包含两个 named script_score 子句: - `exact_text_knn_query`: 对文本向量执行精确点积 - `exact_image_knn_query`: 对图片向量执行精确点积 - 当前采用 `score_mode=total` 且 `rescore_query_weight=0.0`,**只补分不改排序**,exact 分仅出现在 `matched_queries` 中 3. **统一向量得分 Boost 逻辑** (`search/es_query_builder.py`) - 新增 `_get_knn_plan()` 方法,集中管理文本/图片 KNN 的 boost 计算规则 - 支持长查询(token 数超过阈值)时文本 boost 额外乘 1.4 倍 - 精确 rescore 与 ANN 召回**共用同一套 boost 规则**,确保分数量纲一致 - 原有 ANN 查询构建逻辑同步迁移至该统一入口 4. **融合阶段得分优先级调整** (`search/rerank_client.py`) - `_build_hit_signal_bundle()` 中统一处理向量得分读取 - 优先从 `matched_queries` 读取 `exact_text_knn_query` / `exact_image_knn_query` - 若不存在则回退到原 `knn_query` / `image_knn_query`(ANN 得分) - 覆盖 coarse_rank、fine_rank、rerank 三个阶段,避免重复补丁 5. **测试覆盖** - `tests/test_es_query_builder.py`: 验证 ANN 与 exact 共用 boost 规则 - `tests/test_search_rerank_window.py`: 验证 rescore 窗口及 named query 正确注入 - `tests/test_rerank_client.py`: 验证 exact 优先、回退 ANN 的逻辑 技术细节 - **精确向量计算脚本** (Painless) ```painless // 文本 (dotProduct + 1.0) / 2.0 (dotProduct(params.query_vector, 'title_embedding') + 1.0) / 2.0 // 图片同理,字段为 'image_embedding.vector' ``` 乘以统一的 boost(来自配置 `knn_text_boost` / `knn_image_boost` 及长查询放大因子)。 - **named query 保留机制** - 主查询中已开启 `include_named_queries_score: true` - rescore 阶段命名的脚本得分会合并到每个 hit 的 `matched_queries` 中 - 通过 `_extract_named_score()` 按名称提取,与原始 ANN 得分访问方式完全一致 - **性能影响** (基于 top160、6 条真实查询、warm-up 后 3 轮平均) - `elasticsearch_search_primary` 耗时: 124.71ms → 136.60ms (+11.89ms, +9.53%) - `total_search` 受其他组件抖动影响较大,不作为主要参考 - 该开销在可接受范围内,未出现超时或资源瓶颈 配置示例 ```yaml search: exact_knn_rescore_enabled: true exact_knn_rescore_window: 160 knn_text_boost: 4.0 knn_image_boost: 4.0 long_query_token_threshold: 8 long_query_text_boost_factor: 1.4 ``` 已知问题与后续计划 - 当前版本经过调参实验发现,开启 exact rescore 后部分 query(强类型约束 + 多风格/颜色相似)的主指标相比 baseline(exact=false)下降约 0.031(0.6009 → 0.5697) - 根因:exact 将 KNN 从稀疏辅助信号变为 dense 排序因子,coarse 阶段排序语义变化,单纯调整现有 `knn_bias/exponent` 无法完全恢复 - 后续迭代方向:**coarse 阶段暂不强制使用 exact**,仅 fine/rerank 优先 exact;或 coarse 采用“ANN 优先,exact 只补缺失”策略,再重新评估 相关文件 - `config/config.yaml` - `search/searcher.py` - `search/es_query_builder.py` - `search/rerank_client.py` - `tests/test_es_query_builder.py` - `tests/test_search_rerank_window.py` - `tests/test_rerank_client.py` - `scripts/evaluation/exact_rescore_coarse_tuning_round2.json` (调参实验记录) -
背景与问题 - 现有粗排/重排依赖 `knn_query` 和 `image_knn_query` 分数,但这两路分数来自 ANN 召回,并非所有进入 rerank_window (160) 的文档都同时命中文本和图片向量召回,导致部分文档得分为 0,影响融合公式的稳定性。 - 简单扩大 ANN 的 k 无法保证 lexical 召回带来的文档也包含两路向量分;二次查询或拉回向量本地计算均有额外开销且实现复杂。 解决方案 采用 ES rescore 机制,在第一次搜索的 `window_size` 内对每个文档执行精确的向量 script_score,并将分数以 named query 形式附加到 `matched_queries` 中,供后续 coarse/rerank 优先使用。 **设计决策**: - **只补分,不改排序**:rescore 使用 `score_mode: total` 且 `rescore_query_weight: 0.0`,原始 `_score` 保持不变,避免干扰现有排序逻辑,风险最小。 - **精确分数命名**:`exact_text_knn_query` 和 `exact_image_knn_query`,便于客户端识别和回退。 - **可配置**:通过 `exact_knn_rescore_enabled` 开关和 `exact_knn_rescore_window` 控制窗口大小,默认 160。 技术实现细节 1. 配置扩展 (`config/config.yaml`, `config/loader.py`) ```yaml exact_knn_rescore_enabled: true exact_knn_rescore_window: 160 ``` 新增配置项并注入到 `RerankConfig`。 2. Searcher 构建 rescore 查询 (`search/searcher.py`) - 在 `_build_es_search_request` 中,当 `enable_rerank=True` 且配置开启时,构造 rescore 对象: - `window_size` = `exact_knn_rescore_window` - `query` 为一个 `bool` 查询,内嵌两个 `script_score` 子查询,分别计算文本和图片向量的点积相似度: ```painless // exact_text_knn_query (dotProduct(params.query_vector, 'title_embedding') + 1.0) / 2.0 // exact_image_knn_query (dotProduct(params.image_query_vector, 'image_embedding.vector') + 1.0) / 2.0 ``` - 每个 `script_score` 都设置 `_name` 为对应的 named query。 - 注意:当前实现的脚本分数**尚未乘以 knn_text_boost / knn_image_boost**,保持与原始 ANN 分数尺度对齐的后续待办。 3. RerankClient 优先读取 exact 分数 (`search/rerank_client.py`) - 在 `_extract_coarse_signals` 中,从文档的 `matched_queries` 里读取 `exact_text_knn_query` 和 `exact_image_knn_query` 分数。 - 若存在且值有效,则用作 `text_knn_score` / `image_knn_score`,并标记 `text_knn_source='exact_text_knn_query'`。 - 若不存在,则回退到原有的 `knn_query` / `image_knn_query` (ANN 分数)。 - 同时保留原始 ANN 分数到 `approx_text_knn_score` / `approx_image_knn_score` 供调试对比。 4. 调试信息增强 - `debug_info.per_result[*].ranking_funnel.coarse_rank.signals` 中输出 exact 分数、回退分数及来源标记,便于线上观察覆盖率和数值分布。 验证结果 - 通过单元测试 `tests/test_rerank_client.py` 和 `tests/test_search_rerank_window.py`,验证 exact 优先级、配置解析及 ES 请求体结构。 - 线上真实查询采样(6 个 query,top160)显示: - **exact 覆盖率达到 100%**(文本和图片均有分),解决了原 ANN 部分缺失的问题。 - 但 exact 分数与原始 ANN 分数存在量级差异(ANN/exact 中位数比值约 4.1 倍),原因是 exact 脚本未乘 boost 因子。 - 当前排名影响:粗排 top10 重叠度最低降至 1/10,最大排名漂移超过 100。 后续计划 1. 对齐 exact 分与 ANN 分的尺度:在 script_score 中乘以 `knn_text_boost` / `knn_image_boost`,并对长查询额外乘 1.4。 2. 重新评估 top10 重叠度和漂移,若收敛则可将 coarse 融合公式整体迁移至 ES rescore 阶段。 3. 当前版本保持“只补分不改排序”的安全策略,已解决核心的分数缺失问题。 涉及文件 - `config/config.yaml` - `config/loader.py` - `search/searcher.py` - `search/rerank_client.py` - `tests/test_rerank_client.py` - `tests/test_search_rerank_window.py`
01 Apr, 2026
2 commits
30 Mar, 2026
1 commit
27 Mar, 2026
4 commits
-
coarse_rank.output_window -> 再做 SKU 选择和 title suffix -> 精排调用轻量 reranker 裁到 fine_rank.output_window -> 最终重排调用现有 reranker,并在最终融合里加入 fine_score。同时把 reranker client/provider 改成了按 service_profile 选不同 service_url,这样 fine/final 可以共用同一套服务代码,只起不同实例。
-
重排融合:之前有knn的配置bias和exponential。现在,文本和图片的embedding相似需要融合,融合方式是dis_max,因此需要配置: 1)各自的权重和tie_breaker 2)整个向量方面的权重(bias和exponential)
25 Mar, 2026
2 commits
-
@config/dictionaries/style_intent_color.csv @config/dictionaries/style_intent_size.csv @query/style_intent.py @search/sku_intent_selector.py 1. 两个csv词典,分为三列, - 英文关键词 - 中文关键词 - 标准属性名称词 三列都可以允许逗号分割。补充的第三列使用在商品属性中,使用的是标准的英文名称 2. 判断意图的时候,中文词用中文翻译名去匹配,如果不存在中文翻译名,则用原始 query,英文词同理 3. SKU 选择的时候,用每一个 SKU 的属性名去匹配。 匹配规则要大幅度简化,并做性能优化: 1)文本匹配规则只需要看规范化后的属性值是否包含了词典配置的第三列"标准属性名称词",如果包含了,则认为匹配成功。 找到第一个匹配成功的即可。如果都没有成功,后面也不再需要用向量匹配。 暂时废弃向量匹配、双向匹配等复杂逻辑。
24 Mar, 2026
2 commits
-
加了一个过滤/降权词典,query中有独立分词匹配到指定的触发词,将过滤带某些分词的商品(比如fitted/修身,过滤宽松、loose、relaxed、baggy,slouchy等商品) 2. reranker的query使用翻译后的
23 Mar, 2026
3 commits
-
combined_fields+best_field+phrase_boost
-
子句都变成了一个带有以下结构的命名布尔查询: must:combined_fields should:加权后的 best_fields 和 phrase 子句 主要改动位于 search/es_query_builder.py,但此次调整沿用了现有语言路由设计,并未引入一次性分支。额外的 should 子句权重现在通过 config/schema.py、config/loader.py、search/searcher.py 以及 config/config.yaml 进行配置驱动,从而保持结构的集中管理。
22 Mar, 2026
2 commits
20 Mar, 2026
3 commits
19 Mar, 2026
2 commits