diff --git a/.cursor/plans/API响应格式优化与SPU索引重构.2.md b/.cursor/plans/API响应格式优化与SPU索引重构.2.md new file mode 100644 index 0000000..ee8d1e3 --- /dev/null +++ b/.cursor/plans/API响应格式优化与SPU索引重构.2.md @@ -0,0 +1,258 @@ + +# API响应格式优化与SPU索引重构 + +## 概述 + +重构搜索系统以支持: + +1. 外部接口友好的API响应格式(移除ES内部格式) +2. SPU维度的索引结构(包含嵌套variants数组) +3. 所有客户共用同一索引(使用tenant_id隔离) +4. 配置简化(移除MySQL相关配置,只保留ES搜索配置) +5. 添加新客户(customer2)测试数据和配置 + +## Phase 1: 配置文件重构 + +### 1.1 创建BASE配置文件 + +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) + +创建通用配置文件,所有使用店匠表的客户共用: + +- 移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` +- 固定索引名称:`search_products` +- SPU级别字段定义(包含嵌套variants) +- 必需字段:`tenant_id` (KEYWORD, required) +- 扁平化价格字段:`min_price`, `max_price`, `compare_at_price` +- 多语言字段:`title_zh`, `title_en`, `description_zh`, `description_en` 等 +- 嵌套variants结构定义 + +### 1.2 创建customer2配置文件 + +**文件**: [`config/schema/customer2/config.yaml`](config/schema/customer2/config.yaml) (NEW) + +基于BASE配置,为customer2创建配置文件: + +- 继承BASE配置结构 +- 定义customer2特定的字段和搜索域 +- 支持多语言(中文、英文) + +### 1.3 更新配置加载器 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- 移除 `mysql_config`, `main_table`, `extension_table` 解析 +- 移除字段配置中的 `source_table`, `source_column` 解析 +- 固定 `es_index_name` 为 `search_products` +- 添加 `tenant_id` 字段验证(必需字段) +- 支持嵌套字段配置(variants) + +### 1.4 更新字段类型定义 + +**文件**: [`config/field_types.py`](config/field_types.py) + +修改: + +- 移除 `FieldConfig` 中的 `source_table`, `source_column` +- 添加嵌套字段支持(nested fields) +- 添加扁平化价格字段类型 + +## Phase 2: 索引结构重构(SPU维度) + +### 2.1 更新Mapping生成器 + +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) + +修改: + +- 生成SPU级别的mapping +- 添加 `tenant_id` 字段(KEYWORD, required) +- 添加嵌套 `variants` 字段(nested type) +- 添加扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) +- 移除SKU级别的字段映射 + +### 2.2 创建SPU数据转换器 + +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) + +创建SPU数据转换器: + +- 从MySQL读取SPU和SKU数据 +- 按SPU聚合SKU数据为variants数组 +- 计算扁平化价格字段(min_price, max_price, compare_at_price) +- 生成SPU级别的ES文档 +- 注入 `tenant_id` 字段 + +### 2.3 更新数据导入脚本 + +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) + +创建店匠数据导入脚本: + +- 从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 按 `spu_id` 和 `tenant_id` 关联数据 +- 使用SPU转换器转换数据 +- 批量导入到ES索引 `search_products` +- 支持 `--tenant-id` 参数 + +## Phase 3: API响应格式重构 + +### 3.1 更新响应模型 + +**文件**: [`api/models.py`](api/models.py) + +修改 `SearchResponse` 模型: + +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `ProductResult` 模型(包含product_id, title, variants, relevance_score等) +- 添加 `VariantResult` 模型(包含variant_id, title, price, sku等) +- 保持 `facets` 格式 +- 添加 `suggestions` 和 `related_searches` 字段(暂时返回空数组) + +### 3.2 创建结果转换器 + +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) + +创建结果格式化器: + +- 将ES返回的 `_hits` 格式转换为外部接口格式 +- 提取SPU级别字段 +- 提取嵌套variants数组 +- 计算 `relevance_score`(从 `_score` 转换) +- 格式化facets结果 +- 生成suggestions和related_searches(暂时返回空数组) + +### 3.3 更新搜索器 + +**文件**: [`search/searcher.py`](search/searcher.py) + +修改: + +- 在搜索查询中添加 `tenant_id` 过滤(必需) +- 更新结果处理逻辑,使用结果格式化器 +- 移除ES内部格式字段(`_id`, `_score`, `_source`) +- 返回格式化的外部接口格式 + +### 3.4 更新API路由 + +**文件**: [`api/routes/search.py`](api/routes/search.py) + +修改: + +- 添加 `tenant_id` 参数(从请求头或查询参数获取) +- 在搜索请求中添加 `tenant_id` 过滤 +- 使用结果格式化器格式化响应 +- 返回新的响应格式 + +## Phase 4: 测试数据生成 + +### 4.1 创建测试数据生成脚本 + +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) + +创建测试数据生成脚本: + +- 生成100条SPU测试数据 +- 为每个SPU生成1-5个SKU变体 +- 包含中文和英文标题 +- 包含价格、库存、图片等字段 +- 输出为MySQL INSERT语句或CSV文件 + +### 4.2 创建数据导入脚本 + +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) + +创建数据导入脚本: + +- 连接MySQL数据库 +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 设置 `tenant_id` 为customer2的ID +- 验证数据导入结果 + +## Phase 5: 测试脚本和文档 + +### 5.1 创建测试脚本 + +**文件**: [`scripts/test_customer2.py`](scripts/test_customer2.py) (NEW) + +创建customer2测试脚本: + +- 测试数据导入 +- 测试搜索API +- 测试多语言搜索 +- 测试facets聚合 +- 验证响应格式 + +### 5.2 创建说明文档 + +**文件**: [`docs/CUSTOMER2_TEST_GUIDE.md`](docs/CUSTOMER2_TEST_GUIDE.md) (NEW) + +创建customer2测试指南: + +- 数据导入步骤 +- 配置说明 +- API测试示例 +- 常见问题解答 + +## Phase 6: 更新设计文档 + +### 6.1 更新设计文档 + +**文件**: [`设计文档.md`](设计文档.md) + +修改: + +- 更新索引结构说明(SPU维度,所有客户共用) +- 更新配置说明(移除MySQL相关配置) +- 更新API响应格式说明 +- 更新数据导入流程说明 +- 添加customer2测试说明 + +## 关键修改点 + +1. **索引结构**: + +- 索引名称:`search_products`(所有客户共用) +- 索引粒度:SPU级别 +- 租户隔离:使用 `tenant_id` 字段过滤 +- 嵌套结构:`variants` 数组包含SKU数据 + +2. **配置简化**: + +- 移除 `mysql_config`, `main_table`, `extension_table` +- 移除字段配置中的 `source_table`, `source_column` +- 只保留ES搜索相关配置 + +3. **API响应格式**: + +- 从 `_hits`, `_source`, `_score` 改为 `results`, `product_id`, `title`, `relevance_score` +- 添加 `variants` 数组 +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) + +4. **数据导入**: + +- 从MySQL读取SPU和SKU数据 +- 按SPU聚合SKU数据 +- 生成SPU级别的ES文档 +- 注入 `tenant_id` 字段 + +### To-dos + +- [ ] 创建BASE配置文件(config/schema/base/config.yaml),移除MySQL相关配置,定义SPU级别字段和嵌套variants结构 +- [ ] 创建customer2配置文件(config/schema/customer2/config.yaml),基于BASE配置定义customer2特定字段 +- [ ] 更新配置加载器(config/config_loader.py),移除MySQL相关配置解析,支持嵌套字段和tenant_id验证 +- [ ] 更新字段类型定义(config/field_types.py),移除source_table和source_column,添加嵌套字段支持 +- [ ] 更新Mapping生成器(indexer/mapping_generator.py),生成SPU级别mapping,添加tenant_id和嵌套variants字段 +- [ ] 创建SPU数据转换器(indexer/spu_transformer.py),从MySQL读取SPU和SKU数据,按SPU聚合为variants数组 +- [ ] 创建店匠数据导入脚本(scripts/ingest_shoplazza.py),支持从MySQL导入SPU和SKU数据到ES +- [ ] 更新响应模型(api/models.py),添加ProductResult和VariantResult模型,修改SearchResponse格式 +- [ ] 创建结果格式化器(api/result_formatter.py),将ES返回格式转换为外部接口友好格式 +- [ ] 更新搜索器(search/searcher.py),添加tenant_id过滤,使用结果格式化器格式化响应 +- [ ] 更新API路由(api/routes/search.py),添加tenant_id参数,返回新的响应格式 +- [ ] 创建测试数据生成脚本(scripts/generate_test_data.py),生成100条SPU测试数据 +- [ ] 创建数据导入脚本(scripts/import_test_data.py),导入测试数据到MySQL +- [ ] 创建customer2测试脚本(scripts/test_customer2.py),测试数据导入和搜索API +- [ ] 创建customer2测试指南(docs/CUSTOMER2_TEST_GUIDE.md),包含数据导入步骤和API测试示例 +- [ ] 更新设计文档(设计文档.md),更新索引结构、配置说明和API响应格式说明 \ No newline at end of file diff --git a/.cursor/plans/API响应格式优化与SPU索引重构.4.md b/.cursor/plans/API响应格式优化与SPU索引重构.4.md new file mode 100644 index 0000000..b05dd58 --- /dev/null +++ b/.cursor/plans/API响应格式优化与SPU索引重构.4.md @@ -0,0 +1,307 @@ + +# API响应格式优化与SPU索引重构 + +## 概述 + +重构搜索系统以实现: + +1. 外部接口友好的API响应格式(移除ES内部格式 `_hits`, `_source`, `_score`) +2. SPU维度的索引结构(包含嵌套variants数组) +3. 所有客户共用同一索引(使用tenant_id隔离) +4. 配置简化(完全移除MySQL相关配置,只保留ES搜索配置) +5. 创建base配置(店匠通用配置)和SPU数据导入流程 + +## 核心设计原则 + +- **配置只关注ES搜索**:配置文件只包含ES字段定义、查询域、排序规则等搜索相关配置 +- **数据灌入流程写死**:数据来源和转换逻辑由Pipeline层(脚本)决定,不在配置中体现 +- **代码简洁无冗余**:不做向后兼容,直接删除不需要的代码 + +## Phase 1: 配置系统重构 + +### 1.1 创建BASE配置文件 + +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) + +创建店匠通用配置文件: + +- **不包含**:`mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` +- **固定索引名称**:`search_products` +- **SPU级别字段定义**: +- `tenant_id` (KEYWORD, required) +- `product_id` (对应SPU的id) +- `title_zh`, `title_en` (多语言标题) +- `description_zh`, `description_en` (多语言描述) +- `min_price`, `max_price`, `compare_at_price` (扁平化价格) +- `vendor`, `product_type`, `tags` 等 +- **嵌套variants字段定义**: +- `variants` (nested type) +- variants包含:`variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 + +### 1.2 移除配置中的MySQL相关字段 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- **删除** `CustomerConfig` 中的 `mysql_config`, `main_table`, `extension_table` 字段定义 +- **删除** `_parse_config` 中解析这些字段的代码 +- **删除** `_parse_field_config` 中解析 `source_table`, `source_column` 的代码 +- 保持其他配置解析逻辑不变 + +**文件**: [`config/field_types.py`](config/field_types.py) + +修改: + +- **删除** `FieldConfig` 中的 `source_table`, `source_column` 字段定义 +- 保持其他字段类型定义不变 + +### 1.3 更新配置验证 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- 添加 `tenant_id` 字段验证(必需字段) +- 移除所有与MySQL/数据源相关的验证逻辑 + +## Phase 2: 索引结构重构(SPU维度) + +### 2.1 更新Mapping生成器 + +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) + +修改: + +- 在 `_generate_mappings` 中: +- 添加 `tenant_id` 字段(KEYWORD, required) +- 支持嵌套 `variants` 字段(nested type) +- 支持扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) +- 确保所有字段映射正确生成 + +### 2.2 创建SPU数据转换器 + +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) + +创建SPU数据转换器(**不依赖配置中的source_table/source_column**): + +- **数据读取**:直接从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表(写死在代码中) +- **数据聚合**:按 `spu_id` 和 `tenant_id` 关联,将SKU数据聚合为variants数组 +- **字段映射**:将SPU和SKU表的字段映射到ES文档字段(写死在代码中) +- **价格计算**:计算 `min_price`, `max_price`, `compare_at_price` +- **向量生成**:支持文本和图片向量生成(复用现有encoder) +- **文档生成**:生成SPU级别的ES文档,包含嵌套variants数组 +- **tenant_id注入**:自动注入 `tenant_id` 字段 + +### 2.3 创建店匠数据导入脚本 + +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) + +创建店匠数据导入脚本: + +- 连接MySQL数据库(连接信息通过参数或环境变量传入) +- 读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 使用SPU转换器转换数据 +- 批量导入到ES索引 `search_products` +- 支持 `--tenant-id` 参数(必需) +- 支持 `--recreate` 参数(重建索引) +- 支持 `--batch-size` 参数 + +## Phase 3: API响应格式重构 + +### 3.1 更新响应模型 + +**文件**: [`api/models.py`](api/models.py) + +修改: + +- **创建** `VariantResult` 模型: +- `variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 +- **创建** `ProductResult` 模型: +- `product_id`, `title`, `handle`, `description`, `vendor`, `product_type`, `tags` +- `price`, `compare_at_price`, `currency`, `image_url`, `in_stock` +- `variants` (List[VariantResult]) +- `relevance_score` (float, 0-1) +- **修改** `SearchResponse` 模型: +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `suggestions` (List[str]) +- 添加 `related_searches` (List[str]) +- 保持 `facets`, `total`, `took_ms` 等字段 + +### 3.2 创建结果格式化器 + +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) + +创建结果格式化器: + +- **方法** `format_search_results(es_hits, max_score) -> List[ProductResult]`: +- 将ES返回的 `_hits` 格式转换为 `ProductResult` 列表 +- 提取SPU级别字段(从 `_source` 中提取) +- 提取嵌套variants数组(从 `_source.variants` 中提取) +- 计算 `relevance_score`(从 `_score` 归一化到0-1,基于max_score) +- 处理缺失字段(提供默认值) +- **方法** `format_facets(es_aggregations, facet_configs) -> List[FacetResult]`: +- 格式化facets结果(保持现有逻辑) +- **方法** `generate_suggestions(query, results) -> List[str]`: +- 生成搜索建议(暂时返回空数组) +- **方法** `generate_related_searches(query, results) -> List[str]`: +- 生成相关搜索(暂时返回空数组) + +### 3.3 更新搜索器 + +**文件**: [`search/searcher.py`](search/searcher.py) + +修改: + +- **添加** `tenant_id` 参数到 `search` 方法(必需) +- **修改** 查询构建:在filter中添加 `tenant_id` 过滤(必需) +- **修改** 结果处理: +- 使用 `ResultFormatter` 格式化结果 +- 返回 `results` 而不是 `hits` +- 移除ES内部格式字段(`_id`, `_score`, `_source`) +- **修改** `SearchResult` 类: +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `suggestions` 和 `related_searches` 字段 + +### 3.4 更新API路由 + +**文件**: [`api/routes/search.py`](api/routes/search.py) + +修改: + +- **添加** `tenant_id` 参数获取: +- 优先从请求头 `X-Tenant-ID` 获取 +- 其次从查询参数 `tenant_id` 获取 +- 如果都没有,返回400错误 +- **修改** 搜索调用: +- 传递 `tenant_id` 给 `searcher.search()` +- **修改** 响应构建: +- 使用格式化后的 `results` +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) + +## Phase 4: DataTransformer重构 + +### 4.1 重构DataTransformer(向后兼容,用于customer1) + +**文件**: [`indexer/data_transformer.py`](indexer/data_transformer.py) + +修改: + +- **保持** 现有逻辑(用于customer1等旧配置) +- **添加** 检查:如果 `field.source_column` 不存在,跳过该字段(向后兼容) +- **注意**:base配置不使用DataTransformer,使用SPU转换器 + +## Phase 5: 测试数据生成 + +### 5.1 创建测试数据生成脚本 + +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) + +创建测试数据生成脚本: + +- 生成100条SPU测试数据(符合 `shoplazza_product_spu` 表结构) +- 为每个SPU生成1-5个SKU变体(符合 `shoplazza_product_sku` 表结构) +- 包含中文和英文标题 +- 包含价格、库存、图片等字段 +- 输出为MySQL INSERT语句或CSV文件 +- 设置 `tenant_id` 为指定值 + +### 5.2 创建数据导入脚本 + +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) + +创建数据导入脚本: + +- 连接MySQL数据库 +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 设置 `tenant_id` 为base客户的ID(如 "base" 或 "1") +- 验证数据导入结果 + +## Phase 6: 测试脚本和文档 + +### 6.1 创建测试脚本 + +**文件**: [`scripts/test_base.py`](scripts/test_base.py) (NEW) + +创建base配置测试脚本: + +- 测试数据导入(使用ingest_shoplazza.py) +- 测试搜索API(验证tenant_id过滤) +- 测试多语言搜索 +- 测试facets聚合 +- **验证响应格式**: +- 确认返回 `results` 而不是 `hits` +- 确认每个result包含 `product_id`, `title`, `variants`, `relevance_score` +- 确认variants数组格式正确 +- 确认没有ES内部格式字段(`_id`, `_score`, `_source`) + +### 6.2 创建说明文档 + +**文件**: [`docs/BASE_CONFIG_GUIDE.md`](docs/BASE_CONFIG_GUIDE.md) (NEW) + +创建base配置测试指南: + +- 数据导入步骤 +- 配置说明(强调不包含MySQL配置) +- API测试示例(包含tenant_id参数) +- 响应格式说明 +- 常见问题解答 + +## Phase 7: 更新设计文档 + +### 7.1 更新设计文档 + +**文件**: [`设计文档.md`](设计文档.md) + +修改: + +- 更新索引结构说明(SPU维度,所有客户共用 `search_products` 索引) +- 更新配置说明(完全移除MySQL相关配置,只保留ES搜索配置) +- 更新API响应格式说明(results格式,非hits格式) +- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息) +- 添加base配置说明 +- 添加tenant_id隔离说明 + +## 关键修改点总结 + +1. **配置系统**: + +- 完全移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` +- 配置只包含ES搜索相关配置 +- 代码简洁,无冗余,无向后兼容逻辑 + +2. **数据转换**: + +- SPU转换器直接从MySQL读取,不依赖配置 +- 数据映射逻辑写死在代码中 +- 支持嵌套variants数组 + +3. **索引结构**: + +- SPU级别索引 +- 嵌套variants字段 +- tenant_id字段(必需) + +4. **API响应**: + +- 从 `hits` 改为 `results` +- 从 `_id`, `_score`, `_source` 改为 `product_id`, `relevance_score`, 结构化字段 +- 包含 `variants` 数组 + +5. **租户隔离**: + +- 所有客户共用 `search_products` 索引 +- 使用 `tenant_id` 字段过滤 +- API必须提供 `tenant_id` 参数 + +### To-dos + +- [ ] Create ResponseTransformer to convert ES hits to Shoplazza format (results, facets, suggestions, related_searches) +- [ ] Update API models: add VariantOption, ProductVariant, ProductResult, update SearchResponse with new format +- [ ] Update search route to use ResponseTransformer and return Shoplazza format +- [ ] Create script to generate 100 SPU+SKU test records for customer2 in Shoplazza tables +- [ ] Create customer2 config.yaml with search-only fields (no pipeline details) +- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure +- [ ] Create customer2 ingestion script that loads from MySQL and uses SPU transformer +- [ ] Create test script and documentation for customer2 setup and testing +- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions \ No newline at end of file diff --git a/.cursor/plans/API响应格式优化与SPU索引重构.5.最终执行.md b/.cursor/plans/API响应格式优化与SPU索引重构.5.最终执行.md new file mode 100644 index 0000000..8619593 --- /dev/null +++ b/.cursor/plans/API响应格式优化与SPU索引重构.5.最终执行.md @@ -0,0 +1,317 @@ + +# API响应格式优化与SPU索引重构 + +## 概述 + +重构搜索系统以实现: + +1. 外部接口友好的API响应格式(移除ES内部格式 `_hits`, `_source`, `_score`) +2. SPU维度的索引结构(包含嵌套variants数组) +3. 所有客户共用同一索引(使用tenant_id隔离) +4. 配置简化(完全移除MySQL相关配置,只保留ES搜索配置) +5. 创建base配置(店匠通用配置)和SPU数据导入流程 + +## 核心设计原则 + +- **配置只关注ES搜索**:配置文件只包含ES字段定义、查询域、排序规则等搜索相关配置 +- **数据灌入流程写死**:数据来源和转换逻辑由Pipeline层(脚本)决定,不在配置中体现 +- **代码简洁无冗余**:不做向后兼容,直接删除不需要的代码 + +## Phase 1: 配置系统重构 + +### 1.1 创建BASE配置文件 + +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) + +创建店匠通用配置文件: + +- **不包含**:`mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` +- **固定索引名称**:`search_products` +- **SPU级别字段定义**(只包含对搜索有帮助的字段): +- `tenant_id` (KEYWORD, required) - 租户隔离 +- `product_id` (KEYWORD) - 商品ID +- `handle` (KEYWORD) - 商品handle,用于精确匹配 +- `title` (TEXT, chinese_ecommerce) - 标题,主要搜索字段 +- `brief` (TEXT, chinese_ecommerce) - 简介,辅助搜索 +- `description` (TEXT, chinese_ecommerce) - 描述,辅助搜索 +- `seo_title` (TEXT, chinese_ecommerce) - SEO标题,提升相关性 +- `seo_description` (TEXT, chinese_ecommerce) - SEO描述,提升相关性 +- `seo_keywords` (TEXT, chinese_ecommerce) - SEO关键词,提升相关性 +- `vendor` (TEXT + KEYWORD) - 供应商/品牌,搜索和过滤 +- `product_type` (TEXT + KEYWORD) - 商品类型,搜索和过滤 +- `tags` (TEXT + KEYWORD) - 标签,搜索和过滤 +- `category` (TEXT + KEYWORD) - 类目,搜索和过滤 +- `min_price`, `max_price`, `compare_at_price` (FLOAT) - 扁平化价格,用于范围过滤 +- `image_url` (KEYWORD) - 主图URL,用于显示(不参与搜索) +- **嵌套variants字段定义**: +- `variants` (nested type) +- variants包含:`variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 +- **注意**:不包含业务逻辑字段(published, inventory_policy, requires_shipping, taxable等) + +### 1.2 移除配置中的MySQL相关字段 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- **删除** `CustomerConfig` 中的 `mysql_config`, `main_table`, `extension_table` 字段定义 +- **删除** `_parse_config` 中解析这些字段的代码 +- **删除** `_parse_field_config` 中解析 `source_table`, `source_column` 的代码 +- 保持其他配置解析逻辑不变 + +**文件**: [`config/field_types.py`](config/field_types.py) + +修改: + +- **删除** `FieldConfig` 中的 `source_table`, `source_column` 字段定义 +- 保持其他字段类型定义不变 + +### 1.3 更新配置验证 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- 添加 `tenant_id` 字段验证(必需字段) +- 移除所有与MySQL/数据源相关的验证逻辑 + +## Phase 2: 索引结构重构(SPU维度) + +### 2.1 更新Mapping生成器 + +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) + +修改: + +- 在 `_generate_mappings` 中: +- 添加 `tenant_id` 字段(KEYWORD, required) +- 支持嵌套 `variants` 字段(nested type) +- 支持扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) +- 确保所有字段映射正确生成 + +### 2.2 创建SPU数据转换器 + +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) + +创建SPU数据转换器(**不依赖配置中的source_table/source_column**): + +- **数据读取**:直接从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表(写死在代码中) +- **数据聚合**:按 `spu_id` 和 `tenant_id` 关联,将SKU数据聚合为variants数组 +- **字段映射**:将SPU和SKU表的字段映射到ES文档字段(写死在代码中) +- **价格计算**:计算 `min_price`, `max_price`, `compare_at_price` +- **向量生成**:支持文本和图片向量生成(复用现有encoder) +- **文档生成**:生成SPU级别的ES文档,包含嵌套variants数组 +- **tenant_id注入**:自动注入 `tenant_id` 字段 + +### 2.3 创建店匠数据导入脚本 + +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) + +创建店匠数据导入脚本: + +- 连接MySQL数据库(连接信息通过参数或环境变量传入) +- 读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 使用SPU转换器转换数据 +- 批量导入到ES索引 `search_products` +- 支持 `--tenant-id` 参数(必需) +- 支持 `--recreate` 参数(重建索引) +- 支持 `--batch-size` 参数 + +## Phase 3: API响应格式重构 + +### 3.1 更新响应模型 + +**文件**: [`api/models.py`](api/models.py) + +修改: + +- **创建** `VariantResult` 模型: +- `variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 +- **创建** `ProductResult` 模型: +- `product_id`, `title`, `handle`, `description`, `vendor`, `product_type`, `tags` +- `price`, `compare_at_price`, `currency`, `image_url`, `in_stock` +- `variants` (List[VariantResult]) +- `relevance_score` (float, 0-1) +- **修改** `SearchResponse` 模型: +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `suggestions` (List[str]) +- 添加 `related_searches` (List[str]) +- 保持 `facets`, `total`, `took_ms` 等字段 + +### 3.2 创建结果格式化器 + +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) + +创建结果格式化器: + +- **方法** `format_search_results(es_hits, max_score) -> List[ProductResult]`: +- 将ES返回的 `_hits` 格式转换为 `ProductResult` 列表 +- 提取SPU级别字段(从 `_source` 中提取) +- 提取嵌套variants数组(从 `_source.variants` 中提取) +- 计算 `relevance_score`(从 `_score` 归一化到0-1,基于max_score) +- 处理缺失字段(提供默认值) +- **方法** `format_facets(es_aggregations, facet_configs) -> List[FacetResult]`: +- 格式化facets结果(保持现有逻辑) +- **方法** `generate_suggestions(query, results) -> List[str]`: +- 生成搜索建议(暂时返回空数组) +- **方法** `generate_related_searches(query, results) -> List[str]`: +- 生成相关搜索(暂时返回空数组) + +### 3.3 更新搜索器 + +**文件**: [`search/searcher.py`](search/searcher.py) + +修改: + +- **添加** `tenant_id` 参数到 `search` 方法(必需) +- **修改** 查询构建:在filter中添加 `tenant_id` 过滤(必需) +- **修改** 结果处理: +- 使用 `ResultFormatter` 格式化结果 +- 返回 `results` 而不是 `hits` +- 移除ES内部格式字段(`_id`, `_score`, `_source`) +- **修改** `SearchResult` 类: +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `suggestions` 和 `related_searches` 字段 + +### 3.4 更新API路由 + +**文件**: [`api/routes/search.py`](api/routes/search.py) + +修改: + +- **添加** `tenant_id` 参数获取: +- 优先从请求头 `X-Tenant-ID` 获取 +- 其次从查询参数 `tenant_id` 获取 +- 如果都没有,返回400错误 +- **修改** 搜索调用: +- 传递 `tenant_id` 给 `searcher.search()` +- **修改** 响应构建: +- 使用格式化后的 `results` +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) + +## Phase 4: DataTransformer重构 + +### 4.1 重构DataTransformer(向后兼容,用于customer1) + +**文件**: [`indexer/data_transformer.py`](indexer/data_transformer.py) + +修改: + +- **保持** 现有逻辑(用于customer1等旧配置) +- **添加** 检查:如果 `field.source_column` 不存在,跳过该字段(向后兼容) +- **注意**:base配置不使用DataTransformer,使用SPU转换器 + +## Phase 5: 测试数据生成 + +### 5.1 创建测试数据生成脚本 + +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) + +创建测试数据生成脚本: + +- 生成100条SPU测试数据(符合 `shoplazza_product_spu` 表结构) +- 为每个SPU生成1-5个SKU变体(符合 `shoplazza_product_sku` 表结构) +- 包含中文和英文标题 +- 包含价格、库存、图片等字段 +- 输出为MySQL INSERT语句或CSV文件 +- 设置 `tenant_id` 为指定值 + +### 5.2 创建数据导入脚本 + +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) + +创建数据导入脚本: + +- 连接MySQL数据库 +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 设置 `tenant_id` 为base客户的ID(如 "base" 或 "1") +- 验证数据导入结果 + +## Phase 6: 测试脚本和文档 + +### 6.1 创建测试脚本 + +**文件**: [`scripts/test_base.py`](scripts/test_base.py) (NEW) + +创建base配置测试脚本: + +- 测试数据导入(使用ingest_shoplazza.py) +- 测试搜索API(验证tenant_id过滤) +- 测试多语言搜索 +- 测试facets聚合 +- **验证响应格式**: +- 确认返回 `results` 而不是 `hits` +- 确认每个result包含 `product_id`, `title`, `variants`, `relevance_score` +- 确认variants数组格式正确 +- 确认没有ES内部格式字段(`_id`, `_score`, `_source`) + +### 6.2 创建说明文档 + +**文件**: [`docs/BASE_CONFIG_GUIDE.md`](docs/BASE_CONFIG_GUIDE.md) (NEW) + +创建base配置测试指南: + +- 数据导入步骤 +- 配置说明(强调不包含MySQL配置) +- API测试示例(包含tenant_id参数) +- 响应格式说明 +- 常见问题解答 + +## Phase 7: 更新设计文档 + +### 7.1 更新设计文档 + +**文件**: [`设计文档.md`](设计文档.md) + +修改: + +- 更新索引结构说明(SPU维度,所有客户共用 `search_products` 索引) +- 更新配置说明(完全移除MySQL相关配置,只保留ES搜索配置) +- 更新API响应格式说明(results格式,非hits格式) +- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息) +- 添加base配置说明 +- 添加tenant_id隔离说明 + +## 关键修改点总结 + +1. **配置系统**: + +- 完全移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` +- 配置只包含ES搜索相关配置 +- 代码简洁,无冗余,无向后兼容逻辑 + +2. **数据转换**: + +- SPU转换器直接从MySQL读取,不依赖配置 +- 数据映射逻辑写死在代码中 +- 支持嵌套variants数组 + +3. **索引结构**: + +- SPU级别索引 +- 嵌套variants字段 +- tenant_id字段(必需) + +4. **API响应**: + +- 从 `hits` 改为 `results` +- 从 `_id`, `_score`, `_source` 改为 `product_id`, `relevance_score`, 结构化字段 +- 包含 `variants` 数组 + +5. **租户隔离**: + +- 所有客户共用 `search_products` 索引 +- 使用 `tenant_id` 字段过滤 +- API必须提供 `tenant_id` 参数 + +### To-dos + +- [ ] Create ResponseTransformer to convert ES hits to Shoplazza format (results, facets, suggestions, related_searches) +- [ ] Update API models: add VariantOption, ProductVariant, ProductResult, update SearchResponse with new format +- [ ] Update search route to use ResponseTransformer and return Shoplazza format +- [ ] Create script to generate 100 SPU+SKU test records for customer2 in Shoplazza tables +- [ ] Create customer2 config.yaml with search-only fields (no pipeline details) +- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure +- [ ] Create customer2 ingestion script that loads from MySQL and uses SPU transformer +- [ ] Create test script and documentation for customer2 setup and testing +- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions \ No newline at end of file diff --git a/.cursor/plans/API响应格式优化与SPU索引重构.纠正.md b/.cursor/plans/API响应格式优化与SPU索引重构.纠正.md new file mode 100644 index 0000000..3c72c7e --- /dev/null +++ b/.cursor/plans/API响应格式优化与SPU索引重构.纠正.md @@ -0,0 +1,232 @@ +# API响应格式优化与SPU索引重构 + +## 概述 + +重构搜索系统以支持: + +1. 外部接口友好的API响应格式(移除ES内部格式) +2. SPU维度的索引结构(包含嵌套variants数组) +3. 所有客户共用同一索引(使用tenant_id隔离) +4. 配置简化(移除MySQL相关配置,只保留ES搜索配置) +5. 添加新客户(customer2)测试数据和配置 + +## Phase 1: 配置文件重构 + +### 1.1 创建BASE配置文件 + +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) + +创建通用配置文件,所有使用店匠表的客户共用: + +- 移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` +- 固定索引名称:`search_products` +- SPU级别字段定义(包含嵌套variants) +- 必需字段:`tenant_id` (KEYWORD, required) +- 扁平化价格字段:`min_price`, `max_price`, `compare_at_price` +- 多语言字段:`title_zh`, `title_en`, `description_zh`, `description_en` 等 +- 嵌套variants结构定义 + +务必注意:对于店匠的店铺,我们应该都通用的用base配置即可,不需要另外单独针对某个店铺新建一套配置,也就是所有店匠的商品都用这个base配置。 +但是允许有其他某个深度定制客户有自己的索引,比如当前有一套索引customer1,我们不用动他,他的数据灌入流程是另外一份,写死的,他的索引配置也是另外一份。也就是我们的搜索服务可以支持多种配置,索引结构变了、字段变了,就是多一分配置,只是店匠多数用户都用base配置即可。 +下面,如果有用到 customer2 的,应该就是指base客户,并注意帮我纠正。 + +### 1.3 更新配置加载器 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- 移除 `mysql_config`, `main_table`, `extension_table` 解析 +- 移除字段配置中的 `source_table`, `source_column` 解析 +- 固定 `es_index_name` 为 `search_products` +- 添加 `tenant_id` 字段验证(必需字段) +- 支持嵌套字段配置(variants) + +### 1.4 更新字段类型定义 + +**文件**: [`config/field_types.py`](config/field_types.py) + +修改: + +- 移除 `FieldConfig` 中的 `source_table`, `source_column` +- 添加嵌套字段支持(nested fields) +- 添加扁平化价格字段类型 + +## Phase 2: 索引结构重构(SPU维度) + +### 2.1 更新Mapping生成器 + +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) + +修改: + +- 生成SPU级别的mapping +- 添加 `tenant_id` 字段(KEYWORD, required) +- 添加嵌套 `variants` 字段(nested type) +- 添加扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) +- 移除SKU级别的字段映射 + +### 2.2 创建SPU数据转换器 + +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) + +创建SPU数据转换器: + +- 从MySQL读取SPU和SKU数据 +- 按SPU聚合SKU数据为variants数组 +- 计算扁平化价格字段(min_price, max_price, compare_at_price) +- 生成SPU级别的ES文档 +- 注入 `tenant_id` 字段 + +### 2.3 更新数据导入脚本 + +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) + +创建店匠数据导入脚本: + +- 从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 按 `spu_id` 和 `tenant_id` 关联数据 +- 使用SPU转换器转换数据 +- 批量导入到ES索引 `search_products` +- 支持 `--tenant-id` 参数 + +## Phase 3: API响应格式重构 + +### 3.1 更新响应模型 + +**文件**: [`api/models.py`](api/models.py) + +修改 `SearchResponse` 模型: + +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `ProductResult` 模型(包含product_id, title, variants, relevance_score等) +- 添加 `VariantResult` 模型(包含variant_id, title, price, sku等) +- 保持 `facets` 格式 +- 添加 `suggestions` 和 `related_searches` 字段(暂时返回空数组) + +### 3.2 创建结果转换器 + +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) + +创建结果格式化器: + +- 将ES返回的 `_hits` 格式转换为外部接口格式 +- 提取SPU级别字段 +- 提取嵌套variants数组 +- 计算 `relevance_score`(从 `_score` 转换) +- 格式化facets结果 +- 生成suggestions和related_searches(暂时返回空数组) + +### 3.3 更新搜索器 + +**文件**: [`search/searcher.py`](search/searcher.py) + +修改: + +- 在搜索查询中添加 `tenant_id` 过滤(必需) +- 更新结果处理逻辑,使用结果格式化器 +- 移除ES内部格式字段(`_id`, `_score`, `_source`) +- 返回格式化的外部接口格式 + +### 3.4 更新API路由 + +**文件**: [`api/routes/search.py`](api/routes/search.py) + +修改: + +- 添加 `tenant_id` 参数(从请求头或查询参数获取) +- 在搜索请求中添加 `tenant_id` 过滤 +- 使用结果格式化器格式化响应 +- 返回新的响应格式 + +## Phase 4: 测试数据生成 + +### 4.1 创建测试数据生成脚本 + +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) + +创建测试数据生成脚本: + +- 生成100条SPU测试数据 +- 为每个SPU生成1-5个SKU变体 +- 包含中文和英文标题 +- 包含价格、库存、图片等字段 +- 输出为MySQL INSERT语句或CSV文件 + +### 4.2 创建数据导入脚本 + +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) + +创建数据导入脚本: + +- 连接MySQL数据库 +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 设置 `tenant_id` 为customer2的ID +- 验证数据导入结果 + +## Phase 5: 测试脚本和文档 + +### 5.1 创建测试脚本 + +**文件**: [`scripts/test_customer2.py`](scripts/test_customer2.py) (NEW) + +创建customer2测试脚本: + +- 测试数据导入 +- 测试搜索API +- 测试多语言搜索 +- 测试facets聚合 +- 验证响应格式 + +### 5.2 创建说明文档 + +**文件**: [`docs/CUSTOMER2_TEST_GUIDE.md`](docs/CUSTOMER2_TEST_GUIDE.md) (NEW) + +创建customer2测试指南: + +- 数据导入步骤 +- 配置说明 +- API测试示例 +- 常见问题解答 + +## Phase 6: 更新设计文档 + +### 6.1 更新设计文档 + +**文件**: [`设计文档.md`](设计文档.md) + +修改: + +- 更新索引结构说明(SPU维度,所有客户共用) +- 更新配置说明(移除MySQL相关配置) +- 更新API响应格式说明 +- 更新数据导入流程说明 +- 添加customer2测试说明 + +## 关键修改点 + +1. **索引结构**: + +- 索引名称:`search_products`(所有客户共用) +- 索引粒度:SPU级别 +- 租户隔离:使用 `tenant_id` 字段过滤 +- 嵌套结构:`variants` 数组包含SKU数据 + +2. **配置简化**: + +- 移除 `mysql_config`, `main_table`, `extension_table` +- 移除字段配置中的 `source_table`, `source_column` +- 只保留ES搜索相关配置 + +3. **API响应格式**: + +- 从 `_hits`, `_source`, `_score` 改为 `results`, `product_id`, `title`, `relevance_score` +- 添加 `variants` 数组 +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) + +4. **数据导入**: + +- 从MySQL读取SPU和SKU数据 +- 按SPU聚合SKU数据 +- 生成SPU级别的ES文档 +- 注入 `tenant_id` 字段 \ No newline at end of file diff --git a/.cursor/plans/API响应格式优化与SPU索引重构3.md b/.cursor/plans/API响应格式优化与SPU索引重构3.md new file mode 100644 index 0000000..0e96eab --- /dev/null +++ b/.cursor/plans/API响应格式优化与SPU索引重构3.md @@ -0,0 +1,252 @@ + +# API响应格式优化与SPU索引重构 + +## 概述 + +重构搜索系统以支持: + +1. 外部接口友好的API响应格式(移除ES内部格式) +2. SPU维度的索引结构(包含嵌套variants数组) +3. 所有客户共用同一索引(使用tenant_id隔离) +4. 配置简化(移除MySQL相关配置,只保留ES搜索配置) +5. 创建base配置(店匠通用配置)和测试数据 + +## Phase 1: 配置文件重构 + +### 1.1 创建BASE配置文件 + +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) + +创建通用配置文件,所有使用店匠表的客户共用: + +- 移除 `mysql_config`, `main_table`, `extension_table` +- 移除字段配置中的 `source_table`, `source_column` +- 固定索引名称:`search_products` +- SPU级别字段定义(包含嵌套variants) +- 必需字段:`tenant_id` (KEYWORD, required) +- 扁平化价格字段:`min_price`, `max_price`, `compare_at_price` +- 多语言字段:`title_zh`, `title_en`, `description_zh`, `description_en` 等 +- 嵌套variants结构定义 + +**注意**:店匠的店铺都使用base配置,不需要单独配置。允许其他深度定制客户(如customer1)有自己的配置。 + +### 1.2 更新配置加载器 + +**文件**: [`config/config_loader.py`](config/config_loader.py) + +修改: + +- 移除 `mysql_config`, `main_table`, `extension_table` 解析(设为可选,向后兼容) +- 移除字段配置中的 `source_table`, `source_column` 解析(设为可选) +- 支持固定 `es_index_name` 为 `search_products`(base配置) +- 添加 `tenant_id` 字段验证(必需字段) +- 支持嵌套字段配置(variants) + +### 1.3 更新字段类型定义 + +**文件**: [`config/field_types.py`](config/field_types.py) + +修改: + +- `FieldConfig` 中的 `source_table`, `source_column` 设为可选(向后兼容) +- 确保嵌套字段支持(nested fields)正常工作 +- 添加扁平化价格字段类型支持 + +## Phase 2: 索引结构重构(SPU维度) + +### 2.1 更新Mapping生成器 + +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) + +修改: + +- 生成SPU级别的mapping +- 添加 `tenant_id` 字段(KEYWORD, required) +- 添加嵌套 `variants` 字段(nested type) +- 添加扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) +- 支持SPU级别字段映射 + +### 2.2 创建SPU数据转换器 + +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) + +创建SPU数据转换器: + +- 从MySQL读取SPU和SKU数据(`shoplazza_product_spu` 和 `shoplazza_product_sku` 表) +- 按SPU聚合SKU数据为variants数组 +- 计算扁平化价格字段(min_price, max_price, compare_at_price) +- 生成SPU级别的ES文档 +- 注入 `tenant_id` 字段 + +### 2.3 创建店匠数据导入脚本 + +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) + +创建店匠数据导入脚本: + +- 从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 按 `spu_id` 和 `tenant_id` 关联数据 +- 使用SPU转换器转换数据 +- 批量导入到ES索引 `search_products` +- 支持 `--tenant-id` 参数 + +## Phase 3: API响应格式重构 + +### 3.1 更新响应模型 + +**文件**: [`api/models.py`](api/models.py) + +修改 `SearchResponse` 模型: + +- 将 `hits` 改为 `results` (List[ProductResult]) +- 添加 `ProductResult` 模型(包含product_id, title, variants, relevance_score等) +- 添加 `VariantResult` 模型(包含variant_id, title, price, sku等) +- 保持 `facets` 格式 +- 添加 `suggestions` 和 `related_searches` 字段(暂时返回空数组) + +### 3.2 创建结果转换器 + +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) + +创建结果格式化器: + +- 将ES返回的 `_hits` 格式转换为外部接口格式 +- 提取SPU级别字段 +- 提取嵌套variants数组 +- 计算 `relevance_score`(从 `_score` 转换,归一化到0-1) +- 格式化facets结果 +- 生成suggestions和related_searches(暂时返回空数组) + +### 3.3 更新搜索器 + +**文件**: [`search/searcher.py`](search/searcher.py) + +修改: + +- 在搜索查询中添加 `tenant_id` 过滤(必需,从请求参数或配置获取) +- 更新结果处理逻辑,使用结果格式化器 +- 移除ES内部格式字段(`_id`, `_score`, `_source`) +- 返回格式化的外部接口格式 + +### 3.4 更新API路由 + +**文件**: [`api/routes/search.py`](api/routes/search.py) + +修改: + +- 添加 `tenant_id` 参数(从请求头 `X-Tenant-ID` 或查询参数 `tenant_id` 获取) +- 在搜索请求中添加 `tenant_id` 过滤 +- 使用结果格式化器格式化响应 +- 返回新的响应格式 + +## Phase 4: 测试数据生成 + +### 4.1 创建测试数据生成脚本 + +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) + +创建测试数据生成脚本: + +- 生成100条SPU测试数据 +- 为每个SPU生成1-5个SKU变体 +- 包含中文和英文标题 +- 包含价格、库存、图片等字段 +- 输出为MySQL INSERT语句或CSV文件 + +### 4.2 创建数据导入脚本 + +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) + +创建数据导入脚本: + +- 连接MySQL数据库 +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 +- 设置 `tenant_id` 为base客户的ID(如 "base" 或 "1") +- 验证数据导入结果 + +## Phase 5: 测试脚本和文档 + +### 5.1 创建测试脚本 + +**文件**: [`scripts/test_base.py`](scripts/test_base.py) (NEW) + +创建base配置测试脚本: + +- 测试数据导入 +- 测试搜索API +- 测试多语言搜索 +- 测试facets聚合 +- 验证响应格式(results格式,非_hits格式) +- 验证tenant_id过滤 + +### 5.2 创建说明文档 + +**文件**: [`docs/BASE_CONFIG_GUIDE.md`](docs/BASE_CONFIG_GUIDE.md) (NEW) + +创建base配置测试指南: + +- 数据导入步骤 +- 配置说明 +- API测试示例 +- 常见问题解答 + +## Phase 6: 更新设计文档 + +### 6.1 更新设计文档 + +**文件**: [`设计文档.md`](设计文档.md) + +修改: + +- 更新索引结构说明(SPU维度,所有客户共用 `search_products` 索引) +- 更新配置说明(移除MySQL相关配置,只保留ES搜索配置) +- 更新API响应格式说明(results格式,非_hits格式) +- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息) +- 添加base配置说明 + +## 关键修改点 + +1. **索引结构**: + +- 索引名称:`search_products`(所有客户共用) +- 索引粒度:SPU级别 +- 租户隔离:使用 `tenant_id` 字段过滤 +- 嵌套结构:`variants` 数组包含SKU数据 + +2. **配置简化**: + +- 移除 `mysql_config`, `main_table`, `extension_table`(设为可选,向后兼容) +- 移除字段配置中的 `source_table`, `source_column`(设为可选) +- 只保留ES搜索相关配置 + +3. **API响应格式**: + +- 从 `_hits`, `_source`, `_score` 改为 `results`, `product_id`, `title`, `relevance_score` +- 添加 `variants` 数组 +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) + +4. **数据导入**: + +- 从MySQL读取SPU和SKU数据(Pipeline层决定) +- 按SPU聚合SKU数据 +- 生成SPU级别的ES文档 +- 注入 `tenant_id` 字段 + +5. **配置架构**: + +- 配置文件只包含搜索引擎关注的内容 +- 数据来源由Pipeline层(脚本/工具)决定 +- 转换器类型由Pipeline选择,不由配置决定 +- 配置文件不引入mysql到ES层次的东西 + +### To-dos + +- [ ] Create ResponseTransformer to convert ES hits to Shoplazza format (results, facets, suggestions, related_searches) +- [ ] Update API models: add VariantOption, ProductVariant, ProductResult, update SearchResponse with new format +- [ ] Update search route to use ResponseTransformer and return Shoplazza format +- [ ] Create script to generate 100 SPU+SKU test records for customer2 in Shoplazza tables +- [ ] Create customer2 config.yaml with search-only fields (no pipeline details) +- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure +- [ ] Create customer2 ingestion script that loads from MySQL and uses SPU transformer +- [ ] Create test script and documentation for customer2 setup and testing +- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions \ No newline at end of file -- libgit2 0.21.2