14 Apr, 2026
2 commits
-
2. +service_enabled_by_config() { reranker|reranker-fine|translator 如果被关闭,则run.sh all 不启动该服务
09 Apr, 2026
3 commits
-
本次迭代对检索系统的内容复化模块进行了较大规模的重构,将原先硬编码的“仅服饰(apparel)”品类拓展至 taxonomy.md 中定义的所有品类,同时优化了代码结构,降低了扩展新品类的成本。核心设计采用注册表模式(profile registry),按品类 profile 分组进行批处理,并明确区分双语(zh+en)与仅英文(en)输出策略。 【修改内容】 1. 品类支持范围扩展 - 新增支持的品类:3c、bags、pet_supplies、electronics、outdoor、home_appliances、home_living、wigs、beauty、accessories、toys、shoes、sports、others - 所有新品类在 taxonomy 输出阶段仅返回 en 字段,避免多语言字段膨胀 - 保留服饰(apparel)品类的双语输出(zh + en),维持原有业务兼容性 2. 核心代码重构 - `indexer/product_enrich.py` - 新增 `TAXONOMY_PROFILES` 注册表,以数据驱动方式定义每个品类的输出语言、prompt 映射、taxonomy 字段集合 - 重写 `_enrich_taxonomy_batch`:按 profile 分组批量调用 LLM,避免为每个品类编写独立分支 - 引入 `_infer_profile_from_category()` 函数,从 SPU 的 category 字段自动推断所属 profile(用于内部索引路径,解决混合目录默认 fallback 到服饰的问题) - `indexer/product_enrich_prompts.py` - 将原有单一服饰 prompt 重构为 `PROMPT_TEMPLATES` 字典,按 profile 存储不同提示词 - 所有非服饰品类共享一套精简提示模板,仅要求输出 en 字段 - `indexer/document_transformer.py` - 在构建 enrichment 请求时传递 category 信息,供下游按 profile 路由 - 调整 `_build_enrich_batch` 逻辑,使批量请求支持混合品类并正确分组 - `indexer/indexer.py`(API 层) - `/indexer/enrich-content` 接口的请求模型增加可选的 `category_profile` 字段,允许调用方显式指定品类;未指定时由服务端自动推断 - 更新参数校验与错误处理,新增对 `others` 等兜底品类的支持 3. 文档同步更新 - `docs/搜索API对接指南-05-索引接口(Indexer).md`:增加品类 profile 参数说明,标注非服饰品类 taxonomy 仅返回 en 字段 - `docs/搜索API对接指南-07-微服务接口(Embedding-Reranker-Translation).md`:更新 enrichment 微服务的调用示例,体现多品类分组批处理 - `taxonomy.md`:补充各品类的字段清单,明确 en 字段为所有非服饰品类的唯一输出 【技术细节】 - **注册表设计**: ```python TAXONOMY_PROFILES = { "apparel": {"lang": ["zh", "en"], "prompt_key": "apparel", "fields": [...]}, "3c": {"lang": ["en"], "prompt_key": "default", "fields": [...]}, \# ... } ``` 新增品类只需在注册表中添加一项,并确保 `PROMPT_TEMPLATES` 中存在对应的 prompt_key,无需修改控制流逻辑。 - **按 profile 分组批处理**: - 原有实现:所有产品混在一起,使用同一套服饰 prompt,导致非服饰产品被错误填充。 - 重构后:`_enrich_taxonomy_batch` 先根据每个产品的 profile 分组,每组独立构造 LLM 请求,响应结果再按原始顺序合并。分组粒度可配置,避免小分组带来的过多请求开销。 - **自动品类推断**: - 对于内部索引(非显式调用 enrichment 接口的场景),通过 `_infer_profile_from_category` 解析 SPU 的 `category_l1/l2/l3` 字段,映射到最匹配的 profile。映射规则基于关键词匹配(如“手机”->“3c”,“狗粮”->“pet_supplies”),未匹配时 fallback 到 `apparel` 以保证系统平稳过渡。 - **输出字段裁剪**: - 由于 Elasticsearch mapping 中 `enriched_taxonomy_attributes.value` 字段仅存储单个值(不分语言),非服饰品类的 LLM 输出直接写入该字段;服饰品类则使用动态模板 `value.zh` 和 `value.en`。代码中通过 `_apply_lang_output` 函数统一处理。 - **代码量与可维护性**: - 虽然因新增大量品类定义导致总行数略有增长(~+180 行),但条件分支数量从 5 处减少到 1 处(仅 profile 查找)。新增品类的平均成本仅为注册表 3 行 + prompt 模板 10 行,无需改动核心 enrichment 循环。 【影响文件】 - `indexer/product_enrich.py` - `indexer/product_enrich_prompts.py` - `indexer/document_transformer.py` - `indexer/indexer.py` - `docs/搜索API对接指南-05-索引接口(Indexer).md` - `docs/搜索API对接指南-07-微服务接口(Embedding-Reranker-Translation).md` - `taxonomy.md` - `tests/test_product_enrich_partial_mode.py`(适配多 profile 测试用例) - `tests/test_llm_enrichment_batch_fill.py` - `tests/test_process_products_batching.py` 【测试验证】 - 执行单元测试与集成测试:`pytest tests/test_product_enrich_partial_mode.py tests/test_llm_enrichment_batch_fill.py tests/test_process_products_batching.py tests/ci/test_service_api_contracts.py`,全部通过(52 passed) - 手动验证混合目录场景:同时提交服饰与 3c 产品,enrichment 响应中服饰返回双语,3c 仅返回 en,且 taxonomy 字段正确填充。 - 编译检查:`py_compile` 所有修改模块无语法错误。 【注意事项】 - 本次重构未改变现有服饰品类的行为,API 向后兼容(未指定 profile 时仍按服饰处理)。 - 若后续需为某品类增加双语支持,只需修改注册表中的 `lang` 列表并补充 prompt 模板,无需改动其他逻辑。 -
category_taxonomy_profile - 原 analysis_kinds 混用了“增强类型”(content/taxonomy)与“品类特定配置”,不利于扩展不同品类的 taxonomy 分析(如 3C、家居等) - 新增 enrichment_scopes 参数:支持 generic(通用增强,产出 qanchors/enriched_tags/enriched_attributes)和 category_taxonomy(品类增强,产出 enriched_taxonomy_attributes) - 新增 category_taxonomy_profile 参数:指定品类增强使用哪套 profile(当前内置 apparel),每套 profile 包含独立的 prompt、输出列定义、解析规则及缓存版本 - 保留 analysis_kinds 作为兼容别名,避免破坏现有调用方 - 重构内部 taxonomy 分析为 profile registry 模式:新增 _get_taxonomy_schema(profile_name) 函数,根据 profile 动态返回对应的 AnalysisSchema - 缓存 key 现在按“分析类型 + profile + schema 指纹 + 输入字段哈希”隔离,确保不同品类、不同 prompt 版本自动失效 - 更新 API 文档及微服务接口文档,明确新参数语义与使用示例 技术细节: - 修改入口:api/routes/indexer.py 中 enrich-content 端点,解析新参数并向下传递 - 核心逻辑:indexer/product_enrich.py 中 enrich_products_batch 增加 profile 参数;_process_batch_for_schema 根据 scope 和 profile 动态获取 schema - 兼容层:若请求同时提供 analysis_kinds,则映射为 enrichment_scopes(content→generic,taxonomy→category_taxonomy),category_taxonomy_profile 默认为 "apparel" - 测试覆盖:新增 enrichment_scopes 组合、profile 切换及兼容模式测试
-
- `/indexer/enrich-content` 路由`enriched_taxonomy_attributes` 与 `enriched_attributes` 一并返回 - 新增请求参数 `analysis_kinds`(可选,默认 `["content", "taxonomy"]`),允许调用方按需选择内容分析类型,为后续扩展和成本控制预留空间 - 重构缓存策略:将 `content` 与 `taxonomy` 两类分析的缓存完全隔离,缓存 key 包含 prompt 模板、表头、输出字段定义(即 schema 指纹),确保提示词或解析规则变更时自动失效 - 缓存 key 仅依赖真正参与 LLM 输入的字段(`title`、`brief`、`description`),`image_url`、`tenant_id`、`spu_id` 不再污染缓存键,提高缓存命中率 - 更新 API 文档(`docs/搜索API对接指南-05-索引接口(Indexer).md`),说明新增参数与返回字段 技术细节: - 路由层调整:在 `api/routes/indexer.py` 的 enrich-content 端点中,将 `product_enrich.enrich_products_batch` 返回的 `enriched_taxonomy_attributes` 字段显式加入 HTTP 响应体 - `analysis_kinds` 参数透传至底层 `enrich_products_batch`,支持按需跳过某一类分析(如仅需 taxonomy 时减少 LLM 调用) - 缓存指纹计算位于 `product_enrich.py` 的 `_get_cache_key` 函数,对每种 `AnalysisSchema` 独立生成;版本号通过 `schema.version` 或 prompt 内容哈希隐式包含 - 测试覆盖:新增 `analysis_kinds` 组合场景及缓存隔离测试
01 Apr, 2026
1 commit
-
现在的行为(按你的路径) 用途 路径(相对仓库根 PROJECT_ROOT) 评估主日志(CLI + framework 的 INFO) logs/eval.log LLM 全量 prompt / 原始响应 logs/verbose/eval_verbose.log 实现要点: constants.py:EVAL_LOG_DIR、EVAL_VERBOSE_LOG_DIR、EVAL_LOG_FILE、EVAL_VERBOSE_LOG_FILE。 logging_setup.py:setup_eval_logging() 给名为 search_eval 的 logger 挂 文件 + stderr,只初始化一次;build_annotation_set.py / serve_eval_web.py 走的 eval_framework.cli.main() 开头会先调用。 cli.py:原来的 print 改为 search_eval.cli 的 logging.info;启动时写一条 CLI start command=... log_file=... 到 logs/eval.log。 framework.py:rebuild 相关 print 改为 search_eval.framework 的 logging.info。 clients.py:verbose 改为写入 logs/verbose/eval_verbose.log;首次需要时调用 setup_eval_logging(),并用 search_eval.info 提示 verbose 文件路径(不再用 print)。
30 Mar, 2026
2 commits
23 Mar, 2026
2 commits
19 Mar, 2026
3 commits
-
推理”,不再是先按原始输入条数切块。也就是说,如果 100 条请求分句后变成 150 个 segments,batch_size=64 时会按 64 + 64 + 22 三批推理,推理完再按原始分句计划合并并还原成 100 条返回。这个改动在 local_seq2seq.py (line 241) 和 local_ctranslate2.py (line 391)。 日志这边也补上了两层你要的关键信息: 分句摘要日志:Translation segmentation summary,会打印输入条数、非空条数、发生分句的输入数、总 segments 数、当前 batch_size、每条输入分成多少段的统计,见 local_seq2seq.py (line 216) 和 local_ctranslate2.py (line 366)。 每个预测批次日志:Translation inference batch,会打印第几批、总批数、该批 segment 数、长度统计、首条预览。CTranslate2 另外还会打印 Translation model batch detail,补充 token 长度和 max_decoding_length,见 local_ctranslate2.py (line 294)。 我也补了测试,覆盖了“分句后再 batching”和“日志中有分句摘要与每批推理日志”,在 test_translation_local_backends.py (line 358)。
18 Mar, 2026
2 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)。
17 Mar, 2026
3 commits
-
多个独立翻译能力”重构。现在业务侧不再把翻译当 provider 选型,QueryParser 和 indexer 统一通过 6006 的 translator service client 调用;真正的能力选择、启用开关、model + scene 路由,都收口到服务端和新的 translation/ 目录里了。 这次的核心改动在 config/services_config.py、providers/translation.py、api/translator_app.py、config/config.yaml 和新的 translation/service.py。配置从旧的 services.translation.provider/providers 改成了 service_url + default_model + default_scene + capabilities,每个能力可独立 enabled;服务端新增了统一的 backend 管理与懒加载,真实实现集中到 translation/backends/qwen_mt.py、translation/backends/llm.py、translation/backends/deepl.py,旧的 query/qwen_mt_translate.py、query/llm_translate.py、query/deepl_provider.py 只保留兼容导出。接口上,/translate 现在标准支持 scene,context 作为兼容别名继续可用,健康检查会返回默认模型、默认场景和已启用能力。
-
- Rename indexer/product_annotator.py to indexer/product_enrich.py and remove CSV-based CLI entrypoint, keeping only in-memory analyze_products API - Introduce dedicated product_enrich logging with separate verbose log file for full LLM requests/responses - Change indexer and /indexer/enrich-content API wiring to use indexer.product_enrich instead of indexer.product_annotator, updating tests and docs accordingly - Switch translate_prompts to share SUPPORTED_INDEX_LANGUAGES from tenant_config_loader and reuse that mapping for language code → display name - Remove hard SUPPORTED_LANGS constraint from LLM content-enrichment flow, driving languages directly from tenant/indexer configuration - Redesign LLM prompt generation to support multi-round, multi-language tables: first round in English, subsequent rounds translate the entire table (headers + cells) into target languages using English instructions
16 Mar, 2026
2 commits
13 Mar, 2026
5 commits
-
2. 翻译限速 对应处理(qwen-mt限速)
12 Mar, 2026
1 commit
11 Mar, 2026
3 commits
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 -
1. 新增 `scripts/init_env.sh` - 若 `.env` 不存在,从 `.env.example` 复制生成 - 支持 `--force`:覆盖 `.env` 并备份为 `.env.bak` - 首次搭建时统一执行:`./scripts/init_env.sh` 2. 统一加载逻辑 `scripts/lib/load_env.sh` - 移除 `activate.sh` 和 `service_ctl.sh` 中的重复解析逻辑 - 使用共享的 `load_env_file`,并改为 `eval "$(printf 'export %s=%q\n' "$key" "$value")"` 安全导出 - 支持含 ``、`$`、空格等特殊字符的值(需在 `.env` 中用引号包裹) 3. 使用方式 - **activate.sh**:`source scripts/lib/load_env.sh` 后调用 `load_env_file` - **service_ctl.sh**:同上,去掉内联的 `load_env_file` 实现 - **create_tenant_index.sh**:改为使用共享 loader,不再用 `set -a; source .env` 4. 文档更新 - **README.md**:在快速开始中加入 `./scripts/init_env.sh` - **docs/QUICKSTART.md**:说明 `init_env.sh` 用法,并强调含特殊字符的密码需加引号 - **.env.example**:补充注释说明引号规则 5. setup.sh - 用 `./scripts/init_env.sh` 替代原先的 `cp .env.example .env` --- **推荐流程**: ```bash ./scripts/create_venv.sh ./scripts/init_env.sh 从 .env.example 生成本地 .env source activate.sh ./run.sh ``` **密码写法**:若密码包含 ``、`$`、`&`、空格等,需加引号,例如: ```env DB_PASSWORD="qY8tgodLoA&KTyQ" ES_PASSWORD="4hOaLaf41y2VuI8y" ```
09 Mar, 2026
2 commits
06 Mar, 2026
1 commit
02 Mar, 2026
3 commits
-
- 新增 suggestion 模块(mapping/builder/service),支持按租户构建 `search_suggestions_tenant_{tenant_id}` 索引 - 新增 `main.py build-suggestions` CLI 与 `scripts/build_suggestions.sh`,支持基于商品 title/qanchors 与近 365 天搜索日志的全量构建 - 实现 `/search/suggestions` 接口(多语言 + 结果直达),并接入前端自动补全使用新的后端 API - 为 suggestion 增加 `README` / `RUNBOOK` / `TROUBLESHOOTING` 文档,更新搜索 API 对接指南与速查表 - 补充 `tests/test_suggestions.py` 单元测试,覆盖语言解析和 SuggestionService 查询流程 Made-with: Cursor -
- 新增 `suggestion` 模块: - `suggestion/mapping.py`:`search_suggestions` mapping 生成(多语言 `completion` + `search_as_you_type`) - `suggestion/builder.py`:全量构建程序(扫描 `search_products` 的 `title/qanchors` + MySQL `shoplazza_search_log`) - `suggestion/service.py`:在线查询服务(suggestion 检索 + 结果直达商品二次查询) - `suggestion/__init__.py` - 接入 API 服务初始化: - `api/app.py` 新增 `SuggestionService` 初始化和 `get_suggestion_service()` - 接口实现: - `api/routes/search.py` 的 `GET /search/suggestions` 从“空框架”改为真实调用 - 支持参数: - `q`, `size`, `language` - `with_results`(是否直达商品) - `result_size`(每条 suggestion 商品数) - `debug` - 继续要求 `X-Tenant-ID`(或 query 的 `tenant_id`) - 模型补充: - `api/models.py` 增加 suggestion 请求/响应字段(`language`, `resolved_language`, `with_results`, `result_size`) - CLI 全量构建命令: - `main.py` 新增 `build-suggestions` - 使用方式: - `python main.py build-suggestions --tenant-id 1 --recreate` - 可选:`--days 30 --batch-size 500 --min-query-len 1 --es-host ...` --- 关键实现逻辑(已编码) - 语言归属优先级(按你要求): - `shoplazza_search_log.language` > `request_params.language` > 脚本/模型兜底 - 候选词聚合键: - `(tenant_id, lang, text_norm)`(文档唯一) - 评分: - 基于 `query_count_30d/7d + qanchor_doc_count + title_doc_count` 的离线分 - 结果直达: - 对每条 suggestion 在 `search_products_tenant_{id}` 做二次查询(`qanchors/title` 组合) --- 变更文件 - `api/app.py` - `api/models.py` - `api/routes/search.py` - `main.py` - `suggestion/__init__.py` - `suggestion/mapping.py` - `suggestion/builder.py` - `suggestion/service.py` -
- 新增 /indexer/build-docs 与 /indexer/build-docs-from-db 接口:前者接收上游传入的 SPU/SKU/Option 原始行数据构建 ES doc(不写 ES),后者在测试场景下基于 tenant_id+spu_ids 内部查库并复用同一套文档构建逻辑 - 调整增量与全量索引 SQL 与聚合逻辑:移除 shoplazza_product_spu.compare_at_price 读取,统一从 SKU 表聚合最大 compare_at_price,修复 1054 列不存在错误,保证 ES 字段 compare_at_price 来源与索引字段说明v2 保持一致 - 更新 SPUDocumentTransformer:完善价格区间计算、compare_at_price 聚合以及多语言字段输出,确保输出结构与 mappings/search_products.json、Java 侧 ProductIndexDocument 完全对齐 - 为 indexer 模块补充 README 与 prompts:系统化说明 Java 调度 + Python 富化的职责划分、翻译缓存方案(Redis translation:{tenant_id}:{target_lang}:{md5(text)})以及 HTTP 接口使用方式 - 更新顶层 README、搜索API对接指南与测试Pipeline说明:增加关于 indexer 专用服务(serve-indexer, 端口6004)、正式文档构建接口以及手动链路验证(MySQL → build-docs → ES 查询对比)的说明 - 清理并修正 ES 诊断脚本 docs/常用查询 - ES.md:统一改为 per-tenant 索引 search_products_tenant_{tenant_id},修正过期字段名(keywords 等)和分面聚合字段(去掉 .keyword,使用当前 mapping 中的字段) Made-with: Cursor
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)。