15 Apr, 2026
1 commit
-
修改内容 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` (调参实验记录)
30 Mar, 2026
3 commits
-
must里面的两个combined_fields查询,boost分别设置为2和0.6,和其他查询条件一起,都放到should里面,设置minimum_should_match==1 2. 如果keywords_query跟combined_fields主查询的query一样,那么不需要再添加了
27 Mar, 2026
3 commits
-
TODO-keywords限定-done.txt
24 Mar, 2026
1 commit
-
加了一个过滤/降权词典,query中有独立分词匹配到指定的触发词,将过滤带某些分词的商品(比如fitted/修身,过滤宽松、loose、relaxed、baggy,slouchy等商品) 2. reranker的query使用翻译后的
23 Mar, 2026
5 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
2 commits
-
## 背景 多语言索引下,用户查询常中英混写;需在解析阶段显式标记脚本类型,并在 BM25 子句中同时覆盖对应语言字段。 ## 方案 ### 1. Query 分析(query_parser.ParsedQuery) - 新增 `contains_chinese`:query 文本含 CJK(沿用 _contains_cjk)。 - 新增 `contains_english`:分词结果中存在「纯英文、len>=3」token(fullmatch 字母及可选连字符)。 - 写入 to_dict、请求 context 中间结果,便于调试与 API 透出。 ### 2. ES 文本召回(es_query_builder._build_advanced_text_query) - 对每个 search_lang 子句:若含英文且子句语言非 en(且租户 index_languages 含 en),合并 en 列字段;若含中文且子句语言非 zh(且含 zh),合并 zh 列字段。 - 合并进来的字段 boost 乘以 `mixed_script_merged_field_boost_scale`(默认 0.8,可在 ESQueryBuilder 构造参数调整)。 - fallback_original_query_* 分支同样应用上述逻辑。 ### 3. 实现整理 - 引入 `MatchFieldSpec = (field_path, boost)`:`_build_match_field_specs` 为唯一权重来源;`_merge_supplemental_lang_field_specs` / `_expand_match_field_specs_for_mixed_script` 在 tuple 上合并与缩放;最后 `_format_match_field_specs` 再格式化为 ES `path^boost`,避免先拼字符串再解析。 ## 测试 - tests/test_query_parser_mixed_language.py:脚本标记与 token 规则。 - tests/test_es_query_builder.py:合并字段、0.8 缩放、index_languages 限制。 Made-with: Cursor
18 Mar, 2026
3 commits
-
核心改动在 rerank_client.py (line 99):fuse_scores_and_resort 现在按 rerank * knn * text 的平滑乘法公式计算,优先从 hit["matched_queries"] 里取 base_query 和 knn_query,并把 _text_score / _knn_score 一并写回调试字段。为了让 KNN 也有名字,我给 top-level knn 加了 name: "knn_query",见 es_query_builder.py (line 273)。搜索执行时会在 rerank 窗口内打开 include_named_queries_score,并在显式排序时加上 track_scores,见 searcher.py (line 400) 和 es_client.py (line 224)。
12 Mar, 2026
1 commit
11 Mar, 2026
1 commit
10 Mar, 2026
4 commits
-
- 配置改为“字段基名 + 动态语言后缀”方案,已不再依赖旧 `indexes`。 [config.yaml](/data/saas-search/config/config.yaml#L17) - `search_fields` / `text_query_strategy` 已进入强校验与解析流程。 [config_loader.py](/data/saas-search/config/config_loader.py#L254) 2. 查询语言计划与翻译等待策略 - `QueryParser` 现在产出 `query_text_by_lang`、`search_langs`、`source_in_index_languages`。 [query_parser.py](/data/saas-search/query/query_parser.py#L41) - 你要求的两种翻译路径都在: - 源语言不在店铺 `index_languages`:`translate_multi_async` + 等待 future - 源语言在 `index_languages`:`translate_multi(..., async_mode=True)`,尽量走缓存 [query_parser.py](/data/saas-search/query/query_parser.py#L284) 3. ES 查询统一文本策略(无 AST 分支) - 主召回按 `search_langs` 动态拼 `field.{lang}`,翻译语种做次权重 `should`。 [es_query_builder.py](/data/saas-search/search/es_query_builder.py#L454) - 布尔 AST 路径已删除,仅保留统一文本策略。 [es_query_builder.py](/data/saas-search/search/es_query_builder.py#L185) 4. LanguageDetector 优化 - 从“拉丁字母默认英文”升级为:脚本优先 + 拉丁语系打分(词典/变音/后缀)。 [language_detector.py](/data/saas-search/query/language_detector.py#L68) 5. 布尔能力清理(补充) - 已删除废弃模块: [boolean_parser.py](/data/saas-search/search/boolean_parser.py) - `search/__init__` 已无相关导出。 [search/__init__.py](/data/saas-search/search/__init__.py) 6. `indexes` 过时收口(补充) - 兼容函数改为基于动态字段生成,不再依赖 `config.indexes`。 [utils.py](/data/saas-search/config/utils.py#L24) - Admin 配置接口改为返回动态字段配置,不再暴露 `num_indexes`。 [admin.py](/data/saas-search/api/routes/admin.py#L52) 7. suggest
09 Mar, 2026
1 commit
11 Feb, 2026
1 commit
-
短查询(token_count ≤ 2):knn_k=30, num_candidates=100, boost=0.15(约原权重 0.6) 中等查询(3–4):knn_k=50, num_candidates=200, boost=0.25(默认) 长查询(token_count ≥ 5):knn_k=80, num_candidates=300, boost=0.35(约原权重 1.4)
06 Feb, 2026
1 commit
-
--- 1. `search/es_query_builder.py`:`_all` 分支 - **普通字段**(如 `tags_all`, `category1_name_all`): - 键以 `_all` 结尾时,先去掉后缀得到 ES 字段名。 - 若值为**数组**:生成 `bool.must`,内含多个 `term`,即多值 **AND**。 - 若值为**单值**:生成一个 `term`。 - **specifications_all**: - 值为 `[{name, value}, ...]` 时,为每一项生成一个 nested 查询,全部放入同一个 `bool.must`,即列表内所有规格条件都要满足(AND)。 原有逻辑不变:不带 `_all` 的字段,数组仍为 OR(`terms`),单值仍为 `term`。 2. `api/models.py`:filters 说明 - 在 `filters` 的 `description` 中补充: - 字段名加 `_all` 表示 AND(如 `tags_all: ['A','B']` 表示同时包含 A 和 B)。 - `specifications_all` 表示列表内所有规格条件都要满足。 3. `docs/搜索API对接指南.md`:文档 - 在 3.3.1 开头说明:任意字段名可加 `_all` 后缀表示多值 AND。 - 在格式示例中增加 `tags_all`、`category1_name_all` 示例。 - 在「支持的值类型」中说明:数组在带 `_all` 时为 AND。 - 新增小节「`*_all` 语义(多值 AND)」:说明用法及 `specifications_all` 行为。 - 在「常用过滤字段」中补充:以上字段均可加 `_all` 后缀。 --- **使用示例** ```json { "filters": { "tags": ["手机", "促销"], "tags_all": ["手机", "促销", "新品"] } } ``` - `tags`:命中「手机」或「促销」或两者都有(OR)。 - `tags_all`:必须同时包含「手机」「促销」「新品」三个标签(AND)。
06 Jan, 2026
2 commits
-
mappings/search_products.json:把原来的 title_zh/title_en/brief_zh/... 改成 按语言 key 的对象结构( /products/_doc/1 { "title": {"en":...} } ) 同时在这些字段下 预置了全部 analyzer 语言: arabic, armenian, basque, brazilian, bulgarian, catalan, chinese, cjk, czech, danish, dutch, english, finnish, french, galician, german, greek, hindi, hungarian, indonesian, italian, norwegian, persian, portuguese, romanian, russian, spanish, swedish, turkish, thai 实现为 type: object + properties,同时满足“按语言灌入”和“按语言 analyzer”。 索引灌入(全量/增量/transformer)已同步改完 indexer/document_transformer.py:输出从 title_zh/title_en/... 改为: title: {<primary_lang>: 原文, en?: 翻译, zh?: 翻译} brief/description/vendor 同理 category_path/category_name_text 也改为语言对象(避免查询侧继续依赖旧字段) indexer/incremental_service.py:embedding 取值从 title_en/title_zh 改为从 title 对象里优先取 en,否则取 zh,否则取任一可用语言。 查询侧与配置、API/文档已同步 search/es_query_builder.py:查询字段统一改成点路径:title.zh / title.en / vendor.zh / vendor.zh.keyword / category_name_text.zh 等。 config/config.yaml:field boosts / indexes 里的字段名同步为新点路径。 API & formatter: api/result_formatter.py 已支持新结构(并保留对旧 *_zh/_en 的兼容兜底)。 api/models.py、相关 docs/examples 里的 vendor_zh.keyword 等已更新为 vendor.zh.keyword。 文档/脚本:docs/、README.md、scripts/ 里所有旧字段名引用已批量替换为新结构。
25 Dec, 2025
1 commit
-
问题:nested 聚合统计的是嵌套文档(specifications 条目)数量,而不是产品(父文档)数量。 修复内容: 在 es_query_builder.py 中:为 specifications 分面的聚合添加了 reverse_nested 子聚合,用于统计产品数量: "aggs": { "product_count": { "reverse_nested": {} } } 在 result_formatter.py 中:更新读取逻辑,从 product_count.doc_count 读取产品数量,而不是直接使用 doc_count。 修复效果: 之前:分面显示 62(统计了 62 个嵌套文档/规格条目) 现在:分面显示实际的产品数量(例如 2),与搜索结果数量一致
20 Dec, 2025
1 commit
08 Dec, 2025
1 commit
05 Dec, 2025
2 commits
-
将 must 子句改为 should 子句的多查询策略 实现以下查询类型: base_query:主查询,使用 AND 操作符和 75% minimum_should_match 翻译查询:跨语言查询,boost=0.4 短语查询:短查询的精确短语匹配 关键词查询:基于提取名词的查询,boost=0.1 添加 _get_match_fields() 方法,支持中英文字段动态映射 4. 关键改进点 minimum_should_match 从 67% 提升到 75% 添加 operator: "AND" 确保所有词都匹配 使用 should 子句实现多策略融合 支持短语查询和关键词查询的智能触发
-
2. queries
04 Dec, 2025
1 commit
-
核心功能: - 添加 multi_select 字段到 FacetConfig(默认为 true) - 实现 post_filter 支持 disjunctive faceting - 后端自动标记 facet 值的 selected 状态 - 支持 specifications 和普通字段的 multi-select 技术改进: - ESQueryBuilder: 分离 conjunctive/disjunctive filters - ResultFormatter: 根据 current_filters 标记 selected - Searcher: 传递 facet_configs 给 query builder 文档更新: - 添加 multi_select_faceting.md 详细文档 - 更新 API 对接指南,说明新功能 - 添加测试脚本 test_multi_select_facet.py 业界标准: - 遵循 Elasticsearch/Algolia/Amazon 的最佳实践 - 提供探索式搜索体验 - 前后端职责清晰分离
03 Dec, 2025
1 commit
-
{ "facets": [ { "field": "category1_name", "size": 15, "type": "terms" }, "specifications.color", "specifications.size" ] } { "facets": [ {"field": "category1_name", "size": 15, "type": "terms"}, {"field": "specifications.color", "size": 10, "type": "terms"}, {"field": "specifications.size", "size": 10, "type": "terms"} ] } 之前是上面的接口形式,主要是考虑 属性的分面, 因为 款式都是有限的 不需要设定 "size": 10, "type": "terms" 这些参数。 但是从接口设计层面,最好按下面这样,这样的话 specifications.color 和 category1_name 的组装格式 完全一样。前端不需要感知 属性分面 和 类别等其他字段分面的差异。
02 Dec, 2025
1 commit
-
query config/ranking config优化
01 Dec, 2025
1 commit
-
不同维度(不同的 name):求交集 相同维度(相同的 name):求并集