Commit d3a4e2594f0d1337504b0036c559c6e622dbc80f
1 parent
1f6d15fa
相关文档
Showing
5 changed files
with
1366 additions
and
0 deletions
Show diff stats
| ... | ... | @@ -0,0 +1,258 @@ |
| 1 | +<!-- b5a93a00-49d7-4266-8dbf-3d3f708334ed 9b4e4bac-df19-49d4-a775-e5ec954010bd --> | |
| 2 | +# API响应格式优化与SPU索引重构 | |
| 3 | + | |
| 4 | +## 概述 | |
| 5 | + | |
| 6 | +重构搜索系统以支持: | |
| 7 | + | |
| 8 | +1. 外部接口友好的API响应格式(移除ES内部格式) | |
| 9 | +2. SPU维度的索引结构(包含嵌套variants数组) | |
| 10 | +3. 所有客户共用同一索引(使用tenant_id隔离) | |
| 11 | +4. 配置简化(移除MySQL相关配置,只保留ES搜索配置) | |
| 12 | +5. 添加新客户(customer2)测试数据和配置 | |
| 13 | + | |
| 14 | +## Phase 1: 配置文件重构 | |
| 15 | + | |
| 16 | +### 1.1 创建BASE配置文件 | |
| 17 | + | |
| 18 | +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) | |
| 19 | + | |
| 20 | +创建通用配置文件,所有使用店匠表的客户共用: | |
| 21 | + | |
| 22 | +- 移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` | |
| 23 | +- 固定索引名称:`search_products` | |
| 24 | +- SPU级别字段定义(包含嵌套variants) | |
| 25 | +- 必需字段:`tenant_id` (KEYWORD, required) | |
| 26 | +- 扁平化价格字段:`min_price`, `max_price`, `compare_at_price` | |
| 27 | +- 多语言字段:`title_zh`, `title_en`, `description_zh`, `description_en` 等 | |
| 28 | +- 嵌套variants结构定义 | |
| 29 | + | |
| 30 | +### 1.2 创建customer2配置文件 | |
| 31 | + | |
| 32 | +**文件**: [`config/schema/customer2/config.yaml`](config/schema/customer2/config.yaml) (NEW) | |
| 33 | + | |
| 34 | +基于BASE配置,为customer2创建配置文件: | |
| 35 | + | |
| 36 | +- 继承BASE配置结构 | |
| 37 | +- 定义customer2特定的字段和搜索域 | |
| 38 | +- 支持多语言(中文、英文) | |
| 39 | + | |
| 40 | +### 1.3 更新配置加载器 | |
| 41 | + | |
| 42 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 43 | + | |
| 44 | +修改: | |
| 45 | + | |
| 46 | +- 移除 `mysql_config`, `main_table`, `extension_table` 解析 | |
| 47 | +- 移除字段配置中的 `source_table`, `source_column` 解析 | |
| 48 | +- 固定 `es_index_name` 为 `search_products` | |
| 49 | +- 添加 `tenant_id` 字段验证(必需字段) | |
| 50 | +- 支持嵌套字段配置(variants) | |
| 51 | + | |
| 52 | +### 1.4 更新字段类型定义 | |
| 53 | + | |
| 54 | +**文件**: [`config/field_types.py`](config/field_types.py) | |
| 55 | + | |
| 56 | +修改: | |
| 57 | + | |
| 58 | +- 移除 `FieldConfig` 中的 `source_table`, `source_column` | |
| 59 | +- 添加嵌套字段支持(nested fields) | |
| 60 | +- 添加扁平化价格字段类型 | |
| 61 | + | |
| 62 | +## Phase 2: 索引结构重构(SPU维度) | |
| 63 | + | |
| 64 | +### 2.1 更新Mapping生成器 | |
| 65 | + | |
| 66 | +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) | |
| 67 | + | |
| 68 | +修改: | |
| 69 | + | |
| 70 | +- 生成SPU级别的mapping | |
| 71 | +- 添加 `tenant_id` 字段(KEYWORD, required) | |
| 72 | +- 添加嵌套 `variants` 字段(nested type) | |
| 73 | +- 添加扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) | |
| 74 | +- 移除SKU级别的字段映射 | |
| 75 | + | |
| 76 | +### 2.2 创建SPU数据转换器 | |
| 77 | + | |
| 78 | +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) | |
| 79 | + | |
| 80 | +创建SPU数据转换器: | |
| 81 | + | |
| 82 | +- 从MySQL读取SPU和SKU数据 | |
| 83 | +- 按SPU聚合SKU数据为variants数组 | |
| 84 | +- 计算扁平化价格字段(min_price, max_price, compare_at_price) | |
| 85 | +- 生成SPU级别的ES文档 | |
| 86 | +- 注入 `tenant_id` 字段 | |
| 87 | + | |
| 88 | +### 2.3 更新数据导入脚本 | |
| 89 | + | |
| 90 | +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) | |
| 91 | + | |
| 92 | +创建店匠数据导入脚本: | |
| 93 | + | |
| 94 | +- 从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 95 | +- 按 `spu_id` 和 `tenant_id` 关联数据 | |
| 96 | +- 使用SPU转换器转换数据 | |
| 97 | +- 批量导入到ES索引 `search_products` | |
| 98 | +- 支持 `--tenant-id` 参数 | |
| 99 | + | |
| 100 | +## Phase 3: API响应格式重构 | |
| 101 | + | |
| 102 | +### 3.1 更新响应模型 | |
| 103 | + | |
| 104 | +**文件**: [`api/models.py`](api/models.py) | |
| 105 | + | |
| 106 | +修改 `SearchResponse` 模型: | |
| 107 | + | |
| 108 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 109 | +- 添加 `ProductResult` 模型(包含product_id, title, variants, relevance_score等) | |
| 110 | +- 添加 `VariantResult` 模型(包含variant_id, title, price, sku等) | |
| 111 | +- 保持 `facets` 格式 | |
| 112 | +- 添加 `suggestions` 和 `related_searches` 字段(暂时返回空数组) | |
| 113 | + | |
| 114 | +### 3.2 创建结果转换器 | |
| 115 | + | |
| 116 | +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) | |
| 117 | + | |
| 118 | +创建结果格式化器: | |
| 119 | + | |
| 120 | +- 将ES返回的 `_hits` 格式转换为外部接口格式 | |
| 121 | +- 提取SPU级别字段 | |
| 122 | +- 提取嵌套variants数组 | |
| 123 | +- 计算 `relevance_score`(从 `_score` 转换) | |
| 124 | +- 格式化facets结果 | |
| 125 | +- 生成suggestions和related_searches(暂时返回空数组) | |
| 126 | + | |
| 127 | +### 3.3 更新搜索器 | |
| 128 | + | |
| 129 | +**文件**: [`search/searcher.py`](search/searcher.py) | |
| 130 | + | |
| 131 | +修改: | |
| 132 | + | |
| 133 | +- 在搜索查询中添加 `tenant_id` 过滤(必需) | |
| 134 | +- 更新结果处理逻辑,使用结果格式化器 | |
| 135 | +- 移除ES内部格式字段(`_id`, `_score`, `_source`) | |
| 136 | +- 返回格式化的外部接口格式 | |
| 137 | + | |
| 138 | +### 3.4 更新API路由 | |
| 139 | + | |
| 140 | +**文件**: [`api/routes/search.py`](api/routes/search.py) | |
| 141 | + | |
| 142 | +修改: | |
| 143 | + | |
| 144 | +- 添加 `tenant_id` 参数(从请求头或查询参数获取) | |
| 145 | +- 在搜索请求中添加 `tenant_id` 过滤 | |
| 146 | +- 使用结果格式化器格式化响应 | |
| 147 | +- 返回新的响应格式 | |
| 148 | + | |
| 149 | +## Phase 4: 测试数据生成 | |
| 150 | + | |
| 151 | +### 4.1 创建测试数据生成脚本 | |
| 152 | + | |
| 153 | +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) | |
| 154 | + | |
| 155 | +创建测试数据生成脚本: | |
| 156 | + | |
| 157 | +- 生成100条SPU测试数据 | |
| 158 | +- 为每个SPU生成1-5个SKU变体 | |
| 159 | +- 包含中文和英文标题 | |
| 160 | +- 包含价格、库存、图片等字段 | |
| 161 | +- 输出为MySQL INSERT语句或CSV文件 | |
| 162 | + | |
| 163 | +### 4.2 创建数据导入脚本 | |
| 164 | + | |
| 165 | +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) | |
| 166 | + | |
| 167 | +创建数据导入脚本: | |
| 168 | + | |
| 169 | +- 连接MySQL数据库 | |
| 170 | +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 171 | +- 设置 `tenant_id` 为customer2的ID | |
| 172 | +- 验证数据导入结果 | |
| 173 | + | |
| 174 | +## Phase 5: 测试脚本和文档 | |
| 175 | + | |
| 176 | +### 5.1 创建测试脚本 | |
| 177 | + | |
| 178 | +**文件**: [`scripts/test_customer2.py`](scripts/test_customer2.py) (NEW) | |
| 179 | + | |
| 180 | +创建customer2测试脚本: | |
| 181 | + | |
| 182 | +- 测试数据导入 | |
| 183 | +- 测试搜索API | |
| 184 | +- 测试多语言搜索 | |
| 185 | +- 测试facets聚合 | |
| 186 | +- 验证响应格式 | |
| 187 | + | |
| 188 | +### 5.2 创建说明文档 | |
| 189 | + | |
| 190 | +**文件**: [`docs/CUSTOMER2_TEST_GUIDE.md`](docs/CUSTOMER2_TEST_GUIDE.md) (NEW) | |
| 191 | + | |
| 192 | +创建customer2测试指南: | |
| 193 | + | |
| 194 | +- 数据导入步骤 | |
| 195 | +- 配置说明 | |
| 196 | +- API测试示例 | |
| 197 | +- 常见问题解答 | |
| 198 | + | |
| 199 | +## Phase 6: 更新设计文档 | |
| 200 | + | |
| 201 | +### 6.1 更新设计文档 | |
| 202 | + | |
| 203 | +**文件**: [`设计文档.md`](设计文档.md) | |
| 204 | + | |
| 205 | +修改: | |
| 206 | + | |
| 207 | +- 更新索引结构说明(SPU维度,所有客户共用) | |
| 208 | +- 更新配置说明(移除MySQL相关配置) | |
| 209 | +- 更新API响应格式说明 | |
| 210 | +- 更新数据导入流程说明 | |
| 211 | +- 添加customer2测试说明 | |
| 212 | + | |
| 213 | +## 关键修改点 | |
| 214 | + | |
| 215 | +1. **索引结构**: | |
| 216 | + | |
| 217 | +- 索引名称:`search_products`(所有客户共用) | |
| 218 | +- 索引粒度:SPU级别 | |
| 219 | +- 租户隔离:使用 `tenant_id` 字段过滤 | |
| 220 | +- 嵌套结构:`variants` 数组包含SKU数据 | |
| 221 | + | |
| 222 | +2. **配置简化**: | |
| 223 | + | |
| 224 | +- 移除 `mysql_config`, `main_table`, `extension_table` | |
| 225 | +- 移除字段配置中的 `source_table`, `source_column` | |
| 226 | +- 只保留ES搜索相关配置 | |
| 227 | + | |
| 228 | +3. **API响应格式**: | |
| 229 | + | |
| 230 | +- 从 `_hits`, `_source`, `_score` 改为 `results`, `product_id`, `title`, `relevance_score` | |
| 231 | +- 添加 `variants` 数组 | |
| 232 | +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) | |
| 233 | + | |
| 234 | +4. **数据导入**: | |
| 235 | + | |
| 236 | +- 从MySQL读取SPU和SKU数据 | |
| 237 | +- 按SPU聚合SKU数据 | |
| 238 | +- 生成SPU级别的ES文档 | |
| 239 | +- 注入 `tenant_id` 字段 | |
| 240 | + | |
| 241 | +### To-dos | |
| 242 | + | |
| 243 | +- [ ] 创建BASE配置文件(config/schema/base/config.yaml),移除MySQL相关配置,定义SPU级别字段和嵌套variants结构 | |
| 244 | +- [ ] 创建customer2配置文件(config/schema/customer2/config.yaml),基于BASE配置定义customer2特定字段 | |
| 245 | +- [ ] 更新配置加载器(config/config_loader.py),移除MySQL相关配置解析,支持嵌套字段和tenant_id验证 | |
| 246 | +- [ ] 更新字段类型定义(config/field_types.py),移除source_table和source_column,添加嵌套字段支持 | |
| 247 | +- [ ] 更新Mapping生成器(indexer/mapping_generator.py),生成SPU级别mapping,添加tenant_id和嵌套variants字段 | |
| 248 | +- [ ] 创建SPU数据转换器(indexer/spu_transformer.py),从MySQL读取SPU和SKU数据,按SPU聚合为variants数组 | |
| 249 | +- [ ] 创建店匠数据导入脚本(scripts/ingest_shoplazza.py),支持从MySQL导入SPU和SKU数据到ES | |
| 250 | +- [ ] 更新响应模型(api/models.py),添加ProductResult和VariantResult模型,修改SearchResponse格式 | |
| 251 | +- [ ] 创建结果格式化器(api/result_formatter.py),将ES返回格式转换为外部接口友好格式 | |
| 252 | +- [ ] 更新搜索器(search/searcher.py),添加tenant_id过滤,使用结果格式化器格式化响应 | |
| 253 | +- [ ] 更新API路由(api/routes/search.py),添加tenant_id参数,返回新的响应格式 | |
| 254 | +- [ ] 创建测试数据生成脚本(scripts/generate_test_data.py),生成100条SPU测试数据 | |
| 255 | +- [ ] 创建数据导入脚本(scripts/import_test_data.py),导入测试数据到MySQL | |
| 256 | +- [ ] 创建customer2测试脚本(scripts/test_customer2.py),测试数据导入和搜索API | |
| 257 | +- [ ] 创建customer2测试指南(docs/CUSTOMER2_TEST_GUIDE.md),包含数据导入步骤和API测试示例 | |
| 258 | +- [ ] 更新设计文档(设计文档.md),更新索引结构、配置说明和API响应格式说明 | |
| 0 | 259 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,307 @@ |
| 1 | +<!-- 2bec2252-690d-478e-9ce8-bc9073ec23ae c3f51467-b81b-47b7-869f-3da700299e26 --> | |
| 2 | +# API响应格式优化与SPU索引重构 | |
| 3 | + | |
| 4 | +## 概述 | |
| 5 | + | |
| 6 | +重构搜索系统以实现: | |
| 7 | + | |
| 8 | +1. 外部接口友好的API响应格式(移除ES内部格式 `_hits`, `_source`, `_score`) | |
| 9 | +2. SPU维度的索引结构(包含嵌套variants数组) | |
| 10 | +3. 所有客户共用同一索引(使用tenant_id隔离) | |
| 11 | +4. 配置简化(完全移除MySQL相关配置,只保留ES搜索配置) | |
| 12 | +5. 创建base配置(店匠通用配置)和SPU数据导入流程 | |
| 13 | + | |
| 14 | +## 核心设计原则 | |
| 15 | + | |
| 16 | +- **配置只关注ES搜索**:配置文件只包含ES字段定义、查询域、排序规则等搜索相关配置 | |
| 17 | +- **数据灌入流程写死**:数据来源和转换逻辑由Pipeline层(脚本)决定,不在配置中体现 | |
| 18 | +- **代码简洁无冗余**:不做向后兼容,直接删除不需要的代码 | |
| 19 | + | |
| 20 | +## Phase 1: 配置系统重构 | |
| 21 | + | |
| 22 | +### 1.1 创建BASE配置文件 | |
| 23 | + | |
| 24 | +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) | |
| 25 | + | |
| 26 | +创建店匠通用配置文件: | |
| 27 | + | |
| 28 | +- **不包含**:`mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` | |
| 29 | +- **固定索引名称**:`search_products` | |
| 30 | +- **SPU级别字段定义**: | |
| 31 | +- `tenant_id` (KEYWORD, required) | |
| 32 | +- `product_id` (对应SPU的id) | |
| 33 | +- `title_zh`, `title_en` (多语言标题) | |
| 34 | +- `description_zh`, `description_en` (多语言描述) | |
| 35 | +- `min_price`, `max_price`, `compare_at_price` (扁平化价格) | |
| 36 | +- `vendor`, `product_type`, `tags` 等 | |
| 37 | +- **嵌套variants字段定义**: | |
| 38 | +- `variants` (nested type) | |
| 39 | +- variants包含:`variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 | |
| 40 | + | |
| 41 | +### 1.2 移除配置中的MySQL相关字段 | |
| 42 | + | |
| 43 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 44 | + | |
| 45 | +修改: | |
| 46 | + | |
| 47 | +- **删除** `CustomerConfig` 中的 `mysql_config`, `main_table`, `extension_table` 字段定义 | |
| 48 | +- **删除** `_parse_config` 中解析这些字段的代码 | |
| 49 | +- **删除** `_parse_field_config` 中解析 `source_table`, `source_column` 的代码 | |
| 50 | +- 保持其他配置解析逻辑不变 | |
| 51 | + | |
| 52 | +**文件**: [`config/field_types.py`](config/field_types.py) | |
| 53 | + | |
| 54 | +修改: | |
| 55 | + | |
| 56 | +- **删除** `FieldConfig` 中的 `source_table`, `source_column` 字段定义 | |
| 57 | +- 保持其他字段类型定义不变 | |
| 58 | + | |
| 59 | +### 1.3 更新配置验证 | |
| 60 | + | |
| 61 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 62 | + | |
| 63 | +修改: | |
| 64 | + | |
| 65 | +- 添加 `tenant_id` 字段验证(必需字段) | |
| 66 | +- 移除所有与MySQL/数据源相关的验证逻辑 | |
| 67 | + | |
| 68 | +## Phase 2: 索引结构重构(SPU维度) | |
| 69 | + | |
| 70 | +### 2.1 更新Mapping生成器 | |
| 71 | + | |
| 72 | +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) | |
| 73 | + | |
| 74 | +修改: | |
| 75 | + | |
| 76 | +- 在 `_generate_mappings` 中: | |
| 77 | +- 添加 `tenant_id` 字段(KEYWORD, required) | |
| 78 | +- 支持嵌套 `variants` 字段(nested type) | |
| 79 | +- 支持扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) | |
| 80 | +- 确保所有字段映射正确生成 | |
| 81 | + | |
| 82 | +### 2.2 创建SPU数据转换器 | |
| 83 | + | |
| 84 | +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) | |
| 85 | + | |
| 86 | +创建SPU数据转换器(**不依赖配置中的source_table/source_column**): | |
| 87 | + | |
| 88 | +- **数据读取**:直接从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表(写死在代码中) | |
| 89 | +- **数据聚合**:按 `spu_id` 和 `tenant_id` 关联,将SKU数据聚合为variants数组 | |
| 90 | +- **字段映射**:将SPU和SKU表的字段映射到ES文档字段(写死在代码中) | |
| 91 | +- **价格计算**:计算 `min_price`, `max_price`, `compare_at_price` | |
| 92 | +- **向量生成**:支持文本和图片向量生成(复用现有encoder) | |
| 93 | +- **文档生成**:生成SPU级别的ES文档,包含嵌套variants数组 | |
| 94 | +- **tenant_id注入**:自动注入 `tenant_id` 字段 | |
| 95 | + | |
| 96 | +### 2.3 创建店匠数据导入脚本 | |
| 97 | + | |
| 98 | +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) | |
| 99 | + | |
| 100 | +创建店匠数据导入脚本: | |
| 101 | + | |
| 102 | +- 连接MySQL数据库(连接信息通过参数或环境变量传入) | |
| 103 | +- 读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 104 | +- 使用SPU转换器转换数据 | |
| 105 | +- 批量导入到ES索引 `search_products` | |
| 106 | +- 支持 `--tenant-id` 参数(必需) | |
| 107 | +- 支持 `--recreate` 参数(重建索引) | |
| 108 | +- 支持 `--batch-size` 参数 | |
| 109 | + | |
| 110 | +## Phase 3: API响应格式重构 | |
| 111 | + | |
| 112 | +### 3.1 更新响应模型 | |
| 113 | + | |
| 114 | +**文件**: [`api/models.py`](api/models.py) | |
| 115 | + | |
| 116 | +修改: | |
| 117 | + | |
| 118 | +- **创建** `VariantResult` 模型: | |
| 119 | +- `variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 | |
| 120 | +- **创建** `ProductResult` 模型: | |
| 121 | +- `product_id`, `title`, `handle`, `description`, `vendor`, `product_type`, `tags` | |
| 122 | +- `price`, `compare_at_price`, `currency`, `image_url`, `in_stock` | |
| 123 | +- `variants` (List[VariantResult]) | |
| 124 | +- `relevance_score` (float, 0-1) | |
| 125 | +- **修改** `SearchResponse` 模型: | |
| 126 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 127 | +- 添加 `suggestions` (List[str]) | |
| 128 | +- 添加 `related_searches` (List[str]) | |
| 129 | +- 保持 `facets`, `total`, `took_ms` 等字段 | |
| 130 | + | |
| 131 | +### 3.2 创建结果格式化器 | |
| 132 | + | |
| 133 | +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) | |
| 134 | + | |
| 135 | +创建结果格式化器: | |
| 136 | + | |
| 137 | +- **方法** `format_search_results(es_hits, max_score) -> List[ProductResult]`: | |
| 138 | +- 将ES返回的 `_hits` 格式转换为 `ProductResult` 列表 | |
| 139 | +- 提取SPU级别字段(从 `_source` 中提取) | |
| 140 | +- 提取嵌套variants数组(从 `_source.variants` 中提取) | |
| 141 | +- 计算 `relevance_score`(从 `_score` 归一化到0-1,基于max_score) | |
| 142 | +- 处理缺失字段(提供默认值) | |
| 143 | +- **方法** `format_facets(es_aggregations, facet_configs) -> List[FacetResult]`: | |
| 144 | +- 格式化facets结果(保持现有逻辑) | |
| 145 | +- **方法** `generate_suggestions(query, results) -> List[str]`: | |
| 146 | +- 生成搜索建议(暂时返回空数组) | |
| 147 | +- **方法** `generate_related_searches(query, results) -> List[str]`: | |
| 148 | +- 生成相关搜索(暂时返回空数组) | |
| 149 | + | |
| 150 | +### 3.3 更新搜索器 | |
| 151 | + | |
| 152 | +**文件**: [`search/searcher.py`](search/searcher.py) | |
| 153 | + | |
| 154 | +修改: | |
| 155 | + | |
| 156 | +- **添加** `tenant_id` 参数到 `search` 方法(必需) | |
| 157 | +- **修改** 查询构建:在filter中添加 `tenant_id` 过滤(必需) | |
| 158 | +- **修改** 结果处理: | |
| 159 | +- 使用 `ResultFormatter` 格式化结果 | |
| 160 | +- 返回 `results` 而不是 `hits` | |
| 161 | +- 移除ES内部格式字段(`_id`, `_score`, `_source`) | |
| 162 | +- **修改** `SearchResult` 类: | |
| 163 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 164 | +- 添加 `suggestions` 和 `related_searches` 字段 | |
| 165 | + | |
| 166 | +### 3.4 更新API路由 | |
| 167 | + | |
| 168 | +**文件**: [`api/routes/search.py`](api/routes/search.py) | |
| 169 | + | |
| 170 | +修改: | |
| 171 | + | |
| 172 | +- **添加** `tenant_id` 参数获取: | |
| 173 | +- 优先从请求头 `X-Tenant-ID` 获取 | |
| 174 | +- 其次从查询参数 `tenant_id` 获取 | |
| 175 | +- 如果都没有,返回400错误 | |
| 176 | +- **修改** 搜索调用: | |
| 177 | +- 传递 `tenant_id` 给 `searcher.search()` | |
| 178 | +- **修改** 响应构建: | |
| 179 | +- 使用格式化后的 `results` | |
| 180 | +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) | |
| 181 | + | |
| 182 | +## Phase 4: DataTransformer重构 | |
| 183 | + | |
| 184 | +### 4.1 重构DataTransformer(向后兼容,用于customer1) | |
| 185 | + | |
| 186 | +**文件**: [`indexer/data_transformer.py`](indexer/data_transformer.py) | |
| 187 | + | |
| 188 | +修改: | |
| 189 | + | |
| 190 | +- **保持** 现有逻辑(用于customer1等旧配置) | |
| 191 | +- **添加** 检查:如果 `field.source_column` 不存在,跳过该字段(向后兼容) | |
| 192 | +- **注意**:base配置不使用DataTransformer,使用SPU转换器 | |
| 193 | + | |
| 194 | +## Phase 5: 测试数据生成 | |
| 195 | + | |
| 196 | +### 5.1 创建测试数据生成脚本 | |
| 197 | + | |
| 198 | +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) | |
| 199 | + | |
| 200 | +创建测试数据生成脚本: | |
| 201 | + | |
| 202 | +- 生成100条SPU测试数据(符合 `shoplazza_product_spu` 表结构) | |
| 203 | +- 为每个SPU生成1-5个SKU变体(符合 `shoplazza_product_sku` 表结构) | |
| 204 | +- 包含中文和英文标题 | |
| 205 | +- 包含价格、库存、图片等字段 | |
| 206 | +- 输出为MySQL INSERT语句或CSV文件 | |
| 207 | +- 设置 `tenant_id` 为指定值 | |
| 208 | + | |
| 209 | +### 5.2 创建数据导入脚本 | |
| 210 | + | |
| 211 | +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) | |
| 212 | + | |
| 213 | +创建数据导入脚本: | |
| 214 | + | |
| 215 | +- 连接MySQL数据库 | |
| 216 | +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 217 | +- 设置 `tenant_id` 为base客户的ID(如 "base" 或 "1") | |
| 218 | +- 验证数据导入结果 | |
| 219 | + | |
| 220 | +## Phase 6: 测试脚本和文档 | |
| 221 | + | |
| 222 | +### 6.1 创建测试脚本 | |
| 223 | + | |
| 224 | +**文件**: [`scripts/test_base.py`](scripts/test_base.py) (NEW) | |
| 225 | + | |
| 226 | +创建base配置测试脚本: | |
| 227 | + | |
| 228 | +- 测试数据导入(使用ingest_shoplazza.py) | |
| 229 | +- 测试搜索API(验证tenant_id过滤) | |
| 230 | +- 测试多语言搜索 | |
| 231 | +- 测试facets聚合 | |
| 232 | +- **验证响应格式**: | |
| 233 | +- 确认返回 `results` 而不是 `hits` | |
| 234 | +- 确认每个result包含 `product_id`, `title`, `variants`, `relevance_score` | |
| 235 | +- 确认variants数组格式正确 | |
| 236 | +- 确认没有ES内部格式字段(`_id`, `_score`, `_source`) | |
| 237 | + | |
| 238 | +### 6.2 创建说明文档 | |
| 239 | + | |
| 240 | +**文件**: [`docs/BASE_CONFIG_GUIDE.md`](docs/BASE_CONFIG_GUIDE.md) (NEW) | |
| 241 | + | |
| 242 | +创建base配置测试指南: | |
| 243 | + | |
| 244 | +- 数据导入步骤 | |
| 245 | +- 配置说明(强调不包含MySQL配置) | |
| 246 | +- API测试示例(包含tenant_id参数) | |
| 247 | +- 响应格式说明 | |
| 248 | +- 常见问题解答 | |
| 249 | + | |
| 250 | +## Phase 7: 更新设计文档 | |
| 251 | + | |
| 252 | +### 7.1 更新设计文档 | |
| 253 | + | |
| 254 | +**文件**: [`设计文档.md`](设计文档.md) | |
| 255 | + | |
| 256 | +修改: | |
| 257 | + | |
| 258 | +- 更新索引结构说明(SPU维度,所有客户共用 `search_products` 索引) | |
| 259 | +- 更新配置说明(完全移除MySQL相关配置,只保留ES搜索配置) | |
| 260 | +- 更新API响应格式说明(results格式,非hits格式) | |
| 261 | +- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息) | |
| 262 | +- 添加base配置说明 | |
| 263 | +- 添加tenant_id隔离说明 | |
| 264 | + | |
| 265 | +## 关键修改点总结 | |
| 266 | + | |
| 267 | +1. **配置系统**: | |
| 268 | + | |
| 269 | +- 完全移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` | |
| 270 | +- 配置只包含ES搜索相关配置 | |
| 271 | +- 代码简洁,无冗余,无向后兼容逻辑 | |
| 272 | + | |
| 273 | +2. **数据转换**: | |
| 274 | + | |
| 275 | +- SPU转换器直接从MySQL读取,不依赖配置 | |
| 276 | +- 数据映射逻辑写死在代码中 | |
| 277 | +- 支持嵌套variants数组 | |
| 278 | + | |
| 279 | +3. **索引结构**: | |
| 280 | + | |
| 281 | +- SPU级别索引 | |
| 282 | +- 嵌套variants字段 | |
| 283 | +- tenant_id字段(必需) | |
| 284 | + | |
| 285 | +4. **API响应**: | |
| 286 | + | |
| 287 | +- 从 `hits` 改为 `results` | |
| 288 | +- 从 `_id`, `_score`, `_source` 改为 `product_id`, `relevance_score`, 结构化字段 | |
| 289 | +- 包含 `variants` 数组 | |
| 290 | + | |
| 291 | +5. **租户隔离**: | |
| 292 | + | |
| 293 | +- 所有客户共用 `search_products` 索引 | |
| 294 | +- 使用 `tenant_id` 字段过滤 | |
| 295 | +- API必须提供 `tenant_id` 参数 | |
| 296 | + | |
| 297 | +### To-dos | |
| 298 | + | |
| 299 | +- [ ] Create ResponseTransformer to convert ES hits to Shoplazza format (results, facets, suggestions, related_searches) | |
| 300 | +- [ ] Update API models: add VariantOption, ProductVariant, ProductResult, update SearchResponse with new format | |
| 301 | +- [ ] Update search route to use ResponseTransformer and return Shoplazza format | |
| 302 | +- [ ] Create script to generate 100 SPU+SKU test records for customer2 in Shoplazza tables | |
| 303 | +- [ ] Create customer2 config.yaml with search-only fields (no pipeline details) | |
| 304 | +- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure | |
| 305 | +- [ ] Create customer2 ingestion script that loads from MySQL and uses SPU transformer | |
| 306 | +- [ ] Create test script and documentation for customer2 setup and testing | |
| 307 | +- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions | |
| 0 | 308 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,317 @@ |
| 1 | +<!-- 2bec2252-690d-478e-9ce8-bc9073ec23ae e6d47a17-19ec-429f-9ffe-054cc6563eec --> | |
| 2 | +# API响应格式优化与SPU索引重构 | |
| 3 | + | |
| 4 | +## 概述 | |
| 5 | + | |
| 6 | +重构搜索系统以实现: | |
| 7 | + | |
| 8 | +1. 外部接口友好的API响应格式(移除ES内部格式 `_hits`, `_source`, `_score`) | |
| 9 | +2. SPU维度的索引结构(包含嵌套variants数组) | |
| 10 | +3. 所有客户共用同一索引(使用tenant_id隔离) | |
| 11 | +4. 配置简化(完全移除MySQL相关配置,只保留ES搜索配置) | |
| 12 | +5. 创建base配置(店匠通用配置)和SPU数据导入流程 | |
| 13 | + | |
| 14 | +## 核心设计原则 | |
| 15 | + | |
| 16 | +- **配置只关注ES搜索**:配置文件只包含ES字段定义、查询域、排序规则等搜索相关配置 | |
| 17 | +- **数据灌入流程写死**:数据来源和转换逻辑由Pipeline层(脚本)决定,不在配置中体现 | |
| 18 | +- **代码简洁无冗余**:不做向后兼容,直接删除不需要的代码 | |
| 19 | + | |
| 20 | +## Phase 1: 配置系统重构 | |
| 21 | + | |
| 22 | +### 1.1 创建BASE配置文件 | |
| 23 | + | |
| 24 | +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) | |
| 25 | + | |
| 26 | +创建店匠通用配置文件: | |
| 27 | + | |
| 28 | +- **不包含**:`mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` | |
| 29 | +- **固定索引名称**:`search_products` | |
| 30 | +- **SPU级别字段定义**(只包含对搜索有帮助的字段): | |
| 31 | +- `tenant_id` (KEYWORD, required) - 租户隔离 | |
| 32 | +- `product_id` (KEYWORD) - 商品ID | |
| 33 | +- `handle` (KEYWORD) - 商品handle,用于精确匹配 | |
| 34 | +- `title` (TEXT, chinese_ecommerce) - 标题,主要搜索字段 | |
| 35 | +- `brief` (TEXT, chinese_ecommerce) - 简介,辅助搜索 | |
| 36 | +- `description` (TEXT, chinese_ecommerce) - 描述,辅助搜索 | |
| 37 | +- `seo_title` (TEXT, chinese_ecommerce) - SEO标题,提升相关性 | |
| 38 | +- `seo_description` (TEXT, chinese_ecommerce) - SEO描述,提升相关性 | |
| 39 | +- `seo_keywords` (TEXT, chinese_ecommerce) - SEO关键词,提升相关性 | |
| 40 | +- `vendor` (TEXT + KEYWORD) - 供应商/品牌,搜索和过滤 | |
| 41 | +- `product_type` (TEXT + KEYWORD) - 商品类型,搜索和过滤 | |
| 42 | +- `tags` (TEXT + KEYWORD) - 标签,搜索和过滤 | |
| 43 | +- `category` (TEXT + KEYWORD) - 类目,搜索和过滤 | |
| 44 | +- `min_price`, `max_price`, `compare_at_price` (FLOAT) - 扁平化价格,用于范围过滤 | |
| 45 | +- `image_url` (KEYWORD) - 主图URL,用于显示(不参与搜索) | |
| 46 | +- **嵌套variants字段定义**: | |
| 47 | +- `variants` (nested type) | |
| 48 | +- variants包含:`variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 | |
| 49 | +- **注意**:不包含业务逻辑字段(published, inventory_policy, requires_shipping, taxable等) | |
| 50 | + | |
| 51 | +### 1.2 移除配置中的MySQL相关字段 | |
| 52 | + | |
| 53 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 54 | + | |
| 55 | +修改: | |
| 56 | + | |
| 57 | +- **删除** `CustomerConfig` 中的 `mysql_config`, `main_table`, `extension_table` 字段定义 | |
| 58 | +- **删除** `_parse_config` 中解析这些字段的代码 | |
| 59 | +- **删除** `_parse_field_config` 中解析 `source_table`, `source_column` 的代码 | |
| 60 | +- 保持其他配置解析逻辑不变 | |
| 61 | + | |
| 62 | +**文件**: [`config/field_types.py`](config/field_types.py) | |
| 63 | + | |
| 64 | +修改: | |
| 65 | + | |
| 66 | +- **删除** `FieldConfig` 中的 `source_table`, `source_column` 字段定义 | |
| 67 | +- 保持其他字段类型定义不变 | |
| 68 | + | |
| 69 | +### 1.3 更新配置验证 | |
| 70 | + | |
| 71 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 72 | + | |
| 73 | +修改: | |
| 74 | + | |
| 75 | +- 添加 `tenant_id` 字段验证(必需字段) | |
| 76 | +- 移除所有与MySQL/数据源相关的验证逻辑 | |
| 77 | + | |
| 78 | +## Phase 2: 索引结构重构(SPU维度) | |
| 79 | + | |
| 80 | +### 2.1 更新Mapping生成器 | |
| 81 | + | |
| 82 | +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) | |
| 83 | + | |
| 84 | +修改: | |
| 85 | + | |
| 86 | +- 在 `_generate_mappings` 中: | |
| 87 | +- 添加 `tenant_id` 字段(KEYWORD, required) | |
| 88 | +- 支持嵌套 `variants` 字段(nested type) | |
| 89 | +- 支持扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) | |
| 90 | +- 确保所有字段映射正确生成 | |
| 91 | + | |
| 92 | +### 2.2 创建SPU数据转换器 | |
| 93 | + | |
| 94 | +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) | |
| 95 | + | |
| 96 | +创建SPU数据转换器(**不依赖配置中的source_table/source_column**): | |
| 97 | + | |
| 98 | +- **数据读取**:直接从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表(写死在代码中) | |
| 99 | +- **数据聚合**:按 `spu_id` 和 `tenant_id` 关联,将SKU数据聚合为variants数组 | |
| 100 | +- **字段映射**:将SPU和SKU表的字段映射到ES文档字段(写死在代码中) | |
| 101 | +- **价格计算**:计算 `min_price`, `max_price`, `compare_at_price` | |
| 102 | +- **向量生成**:支持文本和图片向量生成(复用现有encoder) | |
| 103 | +- **文档生成**:生成SPU级别的ES文档,包含嵌套variants数组 | |
| 104 | +- **tenant_id注入**:自动注入 `tenant_id` 字段 | |
| 105 | + | |
| 106 | +### 2.3 创建店匠数据导入脚本 | |
| 107 | + | |
| 108 | +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) | |
| 109 | + | |
| 110 | +创建店匠数据导入脚本: | |
| 111 | + | |
| 112 | +- 连接MySQL数据库(连接信息通过参数或环境变量传入) | |
| 113 | +- 读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 114 | +- 使用SPU转换器转换数据 | |
| 115 | +- 批量导入到ES索引 `search_products` | |
| 116 | +- 支持 `--tenant-id` 参数(必需) | |
| 117 | +- 支持 `--recreate` 参数(重建索引) | |
| 118 | +- 支持 `--batch-size` 参数 | |
| 119 | + | |
| 120 | +## Phase 3: API响应格式重构 | |
| 121 | + | |
| 122 | +### 3.1 更新响应模型 | |
| 123 | + | |
| 124 | +**文件**: [`api/models.py`](api/models.py) | |
| 125 | + | |
| 126 | +修改: | |
| 127 | + | |
| 128 | +- **创建** `VariantResult` 模型: | |
| 129 | +- `variant_id`, `title`, `price`, `sku`, `stock`, `options` 等 | |
| 130 | +- **创建** `ProductResult` 模型: | |
| 131 | +- `product_id`, `title`, `handle`, `description`, `vendor`, `product_type`, `tags` | |
| 132 | +- `price`, `compare_at_price`, `currency`, `image_url`, `in_stock` | |
| 133 | +- `variants` (List[VariantResult]) | |
| 134 | +- `relevance_score` (float, 0-1) | |
| 135 | +- **修改** `SearchResponse` 模型: | |
| 136 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 137 | +- 添加 `suggestions` (List[str]) | |
| 138 | +- 添加 `related_searches` (List[str]) | |
| 139 | +- 保持 `facets`, `total`, `took_ms` 等字段 | |
| 140 | + | |
| 141 | +### 3.2 创建结果格式化器 | |
| 142 | + | |
| 143 | +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) | |
| 144 | + | |
| 145 | +创建结果格式化器: | |
| 146 | + | |
| 147 | +- **方法** `format_search_results(es_hits, max_score) -> List[ProductResult]`: | |
| 148 | +- 将ES返回的 `_hits` 格式转换为 `ProductResult` 列表 | |
| 149 | +- 提取SPU级别字段(从 `_source` 中提取) | |
| 150 | +- 提取嵌套variants数组(从 `_source.variants` 中提取) | |
| 151 | +- 计算 `relevance_score`(从 `_score` 归一化到0-1,基于max_score) | |
| 152 | +- 处理缺失字段(提供默认值) | |
| 153 | +- **方法** `format_facets(es_aggregations, facet_configs) -> List[FacetResult]`: | |
| 154 | +- 格式化facets结果(保持现有逻辑) | |
| 155 | +- **方法** `generate_suggestions(query, results) -> List[str]`: | |
| 156 | +- 生成搜索建议(暂时返回空数组) | |
| 157 | +- **方法** `generate_related_searches(query, results) -> List[str]`: | |
| 158 | +- 生成相关搜索(暂时返回空数组) | |
| 159 | + | |
| 160 | +### 3.3 更新搜索器 | |
| 161 | + | |
| 162 | +**文件**: [`search/searcher.py`](search/searcher.py) | |
| 163 | + | |
| 164 | +修改: | |
| 165 | + | |
| 166 | +- **添加** `tenant_id` 参数到 `search` 方法(必需) | |
| 167 | +- **修改** 查询构建:在filter中添加 `tenant_id` 过滤(必需) | |
| 168 | +- **修改** 结果处理: | |
| 169 | +- 使用 `ResultFormatter` 格式化结果 | |
| 170 | +- 返回 `results` 而不是 `hits` | |
| 171 | +- 移除ES内部格式字段(`_id`, `_score`, `_source`) | |
| 172 | +- **修改** `SearchResult` 类: | |
| 173 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 174 | +- 添加 `suggestions` 和 `related_searches` 字段 | |
| 175 | + | |
| 176 | +### 3.4 更新API路由 | |
| 177 | + | |
| 178 | +**文件**: [`api/routes/search.py`](api/routes/search.py) | |
| 179 | + | |
| 180 | +修改: | |
| 181 | + | |
| 182 | +- **添加** `tenant_id` 参数获取: | |
| 183 | +- 优先从请求头 `X-Tenant-ID` 获取 | |
| 184 | +- 其次从查询参数 `tenant_id` 获取 | |
| 185 | +- 如果都没有,返回400错误 | |
| 186 | +- **修改** 搜索调用: | |
| 187 | +- 传递 `tenant_id` 给 `searcher.search()` | |
| 188 | +- **修改** 响应构建: | |
| 189 | +- 使用格式化后的 `results` | |
| 190 | +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) | |
| 191 | + | |
| 192 | +## Phase 4: DataTransformer重构 | |
| 193 | + | |
| 194 | +### 4.1 重构DataTransformer(向后兼容,用于customer1) | |
| 195 | + | |
| 196 | +**文件**: [`indexer/data_transformer.py`](indexer/data_transformer.py) | |
| 197 | + | |
| 198 | +修改: | |
| 199 | + | |
| 200 | +- **保持** 现有逻辑(用于customer1等旧配置) | |
| 201 | +- **添加** 检查:如果 `field.source_column` 不存在,跳过该字段(向后兼容) | |
| 202 | +- **注意**:base配置不使用DataTransformer,使用SPU转换器 | |
| 203 | + | |
| 204 | +## Phase 5: 测试数据生成 | |
| 205 | + | |
| 206 | +### 5.1 创建测试数据生成脚本 | |
| 207 | + | |
| 208 | +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) | |
| 209 | + | |
| 210 | +创建测试数据生成脚本: | |
| 211 | + | |
| 212 | +- 生成100条SPU测试数据(符合 `shoplazza_product_spu` 表结构) | |
| 213 | +- 为每个SPU生成1-5个SKU变体(符合 `shoplazza_product_sku` 表结构) | |
| 214 | +- 包含中文和英文标题 | |
| 215 | +- 包含价格、库存、图片等字段 | |
| 216 | +- 输出为MySQL INSERT语句或CSV文件 | |
| 217 | +- 设置 `tenant_id` 为指定值 | |
| 218 | + | |
| 219 | +### 5.2 创建数据导入脚本 | |
| 220 | + | |
| 221 | +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) | |
| 222 | + | |
| 223 | +创建数据导入脚本: | |
| 224 | + | |
| 225 | +- 连接MySQL数据库 | |
| 226 | +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 227 | +- 设置 `tenant_id` 为base客户的ID(如 "base" 或 "1") | |
| 228 | +- 验证数据导入结果 | |
| 229 | + | |
| 230 | +## Phase 6: 测试脚本和文档 | |
| 231 | + | |
| 232 | +### 6.1 创建测试脚本 | |
| 233 | + | |
| 234 | +**文件**: [`scripts/test_base.py`](scripts/test_base.py) (NEW) | |
| 235 | + | |
| 236 | +创建base配置测试脚本: | |
| 237 | + | |
| 238 | +- 测试数据导入(使用ingest_shoplazza.py) | |
| 239 | +- 测试搜索API(验证tenant_id过滤) | |
| 240 | +- 测试多语言搜索 | |
| 241 | +- 测试facets聚合 | |
| 242 | +- **验证响应格式**: | |
| 243 | +- 确认返回 `results` 而不是 `hits` | |
| 244 | +- 确认每个result包含 `product_id`, `title`, `variants`, `relevance_score` | |
| 245 | +- 确认variants数组格式正确 | |
| 246 | +- 确认没有ES内部格式字段(`_id`, `_score`, `_source`) | |
| 247 | + | |
| 248 | +### 6.2 创建说明文档 | |
| 249 | + | |
| 250 | +**文件**: [`docs/BASE_CONFIG_GUIDE.md`](docs/BASE_CONFIG_GUIDE.md) (NEW) | |
| 251 | + | |
| 252 | +创建base配置测试指南: | |
| 253 | + | |
| 254 | +- 数据导入步骤 | |
| 255 | +- 配置说明(强调不包含MySQL配置) | |
| 256 | +- API测试示例(包含tenant_id参数) | |
| 257 | +- 响应格式说明 | |
| 258 | +- 常见问题解答 | |
| 259 | + | |
| 260 | +## Phase 7: 更新设计文档 | |
| 261 | + | |
| 262 | +### 7.1 更新设计文档 | |
| 263 | + | |
| 264 | +**文件**: [`设计文档.md`](设计文档.md) | |
| 265 | + | |
| 266 | +修改: | |
| 267 | + | |
| 268 | +- 更新索引结构说明(SPU维度,所有客户共用 `search_products` 索引) | |
| 269 | +- 更新配置说明(完全移除MySQL相关配置,只保留ES搜索配置) | |
| 270 | +- 更新API响应格式说明(results格式,非hits格式) | |
| 271 | +- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息) | |
| 272 | +- 添加base配置说明 | |
| 273 | +- 添加tenant_id隔离说明 | |
| 274 | + | |
| 275 | +## 关键修改点总结 | |
| 276 | + | |
| 277 | +1. **配置系统**: | |
| 278 | + | |
| 279 | +- 完全移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` | |
| 280 | +- 配置只包含ES搜索相关配置 | |
| 281 | +- 代码简洁,无冗余,无向后兼容逻辑 | |
| 282 | + | |
| 283 | +2. **数据转换**: | |
| 284 | + | |
| 285 | +- SPU转换器直接从MySQL读取,不依赖配置 | |
| 286 | +- 数据映射逻辑写死在代码中 | |
| 287 | +- 支持嵌套variants数组 | |
| 288 | + | |
| 289 | +3. **索引结构**: | |
| 290 | + | |
| 291 | +- SPU级别索引 | |
| 292 | +- 嵌套variants字段 | |
| 293 | +- tenant_id字段(必需) | |
| 294 | + | |
| 295 | +4. **API响应**: | |
| 296 | + | |
| 297 | +- 从 `hits` 改为 `results` | |
| 298 | +- 从 `_id`, `_score`, `_source` 改为 `product_id`, `relevance_score`, 结构化字段 | |
| 299 | +- 包含 `variants` 数组 | |
| 300 | + | |
| 301 | +5. **租户隔离**: | |
| 302 | + | |
| 303 | +- 所有客户共用 `search_products` 索引 | |
| 304 | +- 使用 `tenant_id` 字段过滤 | |
| 305 | +- API必须提供 `tenant_id` 参数 | |
| 306 | + | |
| 307 | +### To-dos | |
| 308 | + | |
| 309 | +- [ ] Create ResponseTransformer to convert ES hits to Shoplazza format (results, facets, suggestions, related_searches) | |
| 310 | +- [ ] Update API models: add VariantOption, ProductVariant, ProductResult, update SearchResponse with new format | |
| 311 | +- [ ] Update search route to use ResponseTransformer and return Shoplazza format | |
| 312 | +- [ ] Create script to generate 100 SPU+SKU test records for customer2 in Shoplazza tables | |
| 313 | +- [ ] Create customer2 config.yaml with search-only fields (no pipeline details) | |
| 314 | +- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure | |
| 315 | +- [ ] Create customer2 ingestion script that loads from MySQL and uses SPU transformer | |
| 316 | +- [ ] Create test script and documentation for customer2 setup and testing | |
| 317 | +- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions | |
| 0 | 318 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,232 @@ |
| 1 | +# API响应格式优化与SPU索引重构 | |
| 2 | + | |
| 3 | +## 概述 | |
| 4 | + | |
| 5 | +重构搜索系统以支持: | |
| 6 | + | |
| 7 | +1. 外部接口友好的API响应格式(移除ES内部格式) | |
| 8 | +2. SPU维度的索引结构(包含嵌套variants数组) | |
| 9 | +3. 所有客户共用同一索引(使用tenant_id隔离) | |
| 10 | +4. 配置简化(移除MySQL相关配置,只保留ES搜索配置) | |
| 11 | +5. 添加新客户(customer2)测试数据和配置 | |
| 12 | + | |
| 13 | +## Phase 1: 配置文件重构 | |
| 14 | + | |
| 15 | +### 1.1 创建BASE配置文件 | |
| 16 | + | |
| 17 | +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) | |
| 18 | + | |
| 19 | +创建通用配置文件,所有使用店匠表的客户共用: | |
| 20 | + | |
| 21 | +- 移除 `mysql_config`, `main_table`, `extension_table`, `source_table`, `source_column` | |
| 22 | +- 固定索引名称:`search_products` | |
| 23 | +- SPU级别字段定义(包含嵌套variants) | |
| 24 | +- 必需字段:`tenant_id` (KEYWORD, required) | |
| 25 | +- 扁平化价格字段:`min_price`, `max_price`, `compare_at_price` | |
| 26 | +- 多语言字段:`title_zh`, `title_en`, `description_zh`, `description_en` 等 | |
| 27 | +- 嵌套variants结构定义 | |
| 28 | + | |
| 29 | +务必注意:对于店匠的店铺,我们应该都通用的用base配置即可,不需要另外单独针对某个店铺新建一套配置,也就是所有店匠的商品都用这个base配置。 | |
| 30 | +但是允许有其他某个深度定制客户有自己的索引,比如当前有一套索引customer1,我们不用动他,他的数据灌入流程是另外一份,写死的,他的索引配置也是另外一份。也就是我们的搜索服务可以支持多种配置,索引结构变了、字段变了,就是多一分配置,只是店匠多数用户都用base配置即可。 | |
| 31 | +下面,如果有用到 customer2 的,应该就是指base客户,并注意帮我纠正。 | |
| 32 | + | |
| 33 | +### 1.3 更新配置加载器 | |
| 34 | + | |
| 35 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 36 | + | |
| 37 | +修改: | |
| 38 | + | |
| 39 | +- 移除 `mysql_config`, `main_table`, `extension_table` 解析 | |
| 40 | +- 移除字段配置中的 `source_table`, `source_column` 解析 | |
| 41 | +- 固定 `es_index_name` 为 `search_products` | |
| 42 | +- 添加 `tenant_id` 字段验证(必需字段) | |
| 43 | +- 支持嵌套字段配置(variants) | |
| 44 | + | |
| 45 | +### 1.4 更新字段类型定义 | |
| 46 | + | |
| 47 | +**文件**: [`config/field_types.py`](config/field_types.py) | |
| 48 | + | |
| 49 | +修改: | |
| 50 | + | |
| 51 | +- 移除 `FieldConfig` 中的 `source_table`, `source_column` | |
| 52 | +- 添加嵌套字段支持(nested fields) | |
| 53 | +- 添加扁平化价格字段类型 | |
| 54 | + | |
| 55 | +## Phase 2: 索引结构重构(SPU维度) | |
| 56 | + | |
| 57 | +### 2.1 更新Mapping生成器 | |
| 58 | + | |
| 59 | +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) | |
| 60 | + | |
| 61 | +修改: | |
| 62 | + | |
| 63 | +- 生成SPU级别的mapping | |
| 64 | +- 添加 `tenant_id` 字段(KEYWORD, required) | |
| 65 | +- 添加嵌套 `variants` 字段(nested type) | |
| 66 | +- 添加扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) | |
| 67 | +- 移除SKU级别的字段映射 | |
| 68 | + | |
| 69 | +### 2.2 创建SPU数据转换器 | |
| 70 | + | |
| 71 | +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) | |
| 72 | + | |
| 73 | +创建SPU数据转换器: | |
| 74 | + | |
| 75 | +- 从MySQL读取SPU和SKU数据 | |
| 76 | +- 按SPU聚合SKU数据为variants数组 | |
| 77 | +- 计算扁平化价格字段(min_price, max_price, compare_at_price) | |
| 78 | +- 生成SPU级别的ES文档 | |
| 79 | +- 注入 `tenant_id` 字段 | |
| 80 | + | |
| 81 | +### 2.3 更新数据导入脚本 | |
| 82 | + | |
| 83 | +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) | |
| 84 | + | |
| 85 | +创建店匠数据导入脚本: | |
| 86 | + | |
| 87 | +- 从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 88 | +- 按 `spu_id` 和 `tenant_id` 关联数据 | |
| 89 | +- 使用SPU转换器转换数据 | |
| 90 | +- 批量导入到ES索引 `search_products` | |
| 91 | +- 支持 `--tenant-id` 参数 | |
| 92 | + | |
| 93 | +## Phase 3: API响应格式重构 | |
| 94 | + | |
| 95 | +### 3.1 更新响应模型 | |
| 96 | + | |
| 97 | +**文件**: [`api/models.py`](api/models.py) | |
| 98 | + | |
| 99 | +修改 `SearchResponse` 模型: | |
| 100 | + | |
| 101 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 102 | +- 添加 `ProductResult` 模型(包含product_id, title, variants, relevance_score等) | |
| 103 | +- 添加 `VariantResult` 模型(包含variant_id, title, price, sku等) | |
| 104 | +- 保持 `facets` 格式 | |
| 105 | +- 添加 `suggestions` 和 `related_searches` 字段(暂时返回空数组) | |
| 106 | + | |
| 107 | +### 3.2 创建结果转换器 | |
| 108 | + | |
| 109 | +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) | |
| 110 | + | |
| 111 | +创建结果格式化器: | |
| 112 | + | |
| 113 | +- 将ES返回的 `_hits` 格式转换为外部接口格式 | |
| 114 | +- 提取SPU级别字段 | |
| 115 | +- 提取嵌套variants数组 | |
| 116 | +- 计算 `relevance_score`(从 `_score` 转换) | |
| 117 | +- 格式化facets结果 | |
| 118 | +- 生成suggestions和related_searches(暂时返回空数组) | |
| 119 | + | |
| 120 | +### 3.3 更新搜索器 | |
| 121 | + | |
| 122 | +**文件**: [`search/searcher.py`](search/searcher.py) | |
| 123 | + | |
| 124 | +修改: | |
| 125 | + | |
| 126 | +- 在搜索查询中添加 `tenant_id` 过滤(必需) | |
| 127 | +- 更新结果处理逻辑,使用结果格式化器 | |
| 128 | +- 移除ES内部格式字段(`_id`, `_score`, `_source`) | |
| 129 | +- 返回格式化的外部接口格式 | |
| 130 | + | |
| 131 | +### 3.4 更新API路由 | |
| 132 | + | |
| 133 | +**文件**: [`api/routes/search.py`](api/routes/search.py) | |
| 134 | + | |
| 135 | +修改: | |
| 136 | + | |
| 137 | +- 添加 `tenant_id` 参数(从请求头或查询参数获取) | |
| 138 | +- 在搜索请求中添加 `tenant_id` 过滤 | |
| 139 | +- 使用结果格式化器格式化响应 | |
| 140 | +- 返回新的响应格式 | |
| 141 | + | |
| 142 | +## Phase 4: 测试数据生成 | |
| 143 | + | |
| 144 | +### 4.1 创建测试数据生成脚本 | |
| 145 | + | |
| 146 | +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) | |
| 147 | + | |
| 148 | +创建测试数据生成脚本: | |
| 149 | + | |
| 150 | +- 生成100条SPU测试数据 | |
| 151 | +- 为每个SPU生成1-5个SKU变体 | |
| 152 | +- 包含中文和英文标题 | |
| 153 | +- 包含价格、库存、图片等字段 | |
| 154 | +- 输出为MySQL INSERT语句或CSV文件 | |
| 155 | + | |
| 156 | +### 4.2 创建数据导入脚本 | |
| 157 | + | |
| 158 | +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) | |
| 159 | + | |
| 160 | +创建数据导入脚本: | |
| 161 | + | |
| 162 | +- 连接MySQL数据库 | |
| 163 | +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 164 | +- 设置 `tenant_id` 为customer2的ID | |
| 165 | +- 验证数据导入结果 | |
| 166 | + | |
| 167 | +## Phase 5: 测试脚本和文档 | |
| 168 | + | |
| 169 | +### 5.1 创建测试脚本 | |
| 170 | + | |
| 171 | +**文件**: [`scripts/test_customer2.py`](scripts/test_customer2.py) (NEW) | |
| 172 | + | |
| 173 | +创建customer2测试脚本: | |
| 174 | + | |
| 175 | +- 测试数据导入 | |
| 176 | +- 测试搜索API | |
| 177 | +- 测试多语言搜索 | |
| 178 | +- 测试facets聚合 | |
| 179 | +- 验证响应格式 | |
| 180 | + | |
| 181 | +### 5.2 创建说明文档 | |
| 182 | + | |
| 183 | +**文件**: [`docs/CUSTOMER2_TEST_GUIDE.md`](docs/CUSTOMER2_TEST_GUIDE.md) (NEW) | |
| 184 | + | |
| 185 | +创建customer2测试指南: | |
| 186 | + | |
| 187 | +- 数据导入步骤 | |
| 188 | +- 配置说明 | |
| 189 | +- API测试示例 | |
| 190 | +- 常见问题解答 | |
| 191 | + | |
| 192 | +## Phase 6: 更新设计文档 | |
| 193 | + | |
| 194 | +### 6.1 更新设计文档 | |
| 195 | + | |
| 196 | +**文件**: [`设计文档.md`](设计文档.md) | |
| 197 | + | |
| 198 | +修改: | |
| 199 | + | |
| 200 | +- 更新索引结构说明(SPU维度,所有客户共用) | |
| 201 | +- 更新配置说明(移除MySQL相关配置) | |
| 202 | +- 更新API响应格式说明 | |
| 203 | +- 更新数据导入流程说明 | |
| 204 | +- 添加customer2测试说明 | |
| 205 | + | |
| 206 | +## 关键修改点 | |
| 207 | + | |
| 208 | +1. **索引结构**: | |
| 209 | + | |
| 210 | +- 索引名称:`search_products`(所有客户共用) | |
| 211 | +- 索引粒度:SPU级别 | |
| 212 | +- 租户隔离:使用 `tenant_id` 字段过滤 | |
| 213 | +- 嵌套结构:`variants` 数组包含SKU数据 | |
| 214 | + | |
| 215 | +2. **配置简化**: | |
| 216 | + | |
| 217 | +- 移除 `mysql_config`, `main_table`, `extension_table` | |
| 218 | +- 移除字段配置中的 `source_table`, `source_column` | |
| 219 | +- 只保留ES搜索相关配置 | |
| 220 | + | |
| 221 | +3. **API响应格式**: | |
| 222 | + | |
| 223 | +- 从 `_hits`, `_source`, `_score` 改为 `results`, `product_id`, `title`, `relevance_score` | |
| 224 | +- 添加 `variants` 数组 | |
| 225 | +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) | |
| 226 | + | |
| 227 | +4. **数据导入**: | |
| 228 | + | |
| 229 | +- 从MySQL读取SPU和SKU数据 | |
| 230 | +- 按SPU聚合SKU数据 | |
| 231 | +- 生成SPU级别的ES文档 | |
| 232 | +- 注入 `tenant_id` 字段 | |
| 0 | 233 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,252 @@ |
| 1 | +<!-- 2bec2252-690d-478e-9ce8-bc9073ec23ae cee9ef6a-2da8-41b5-b37e-12464a8e129a --> | |
| 2 | +# API响应格式优化与SPU索引重构 | |
| 3 | + | |
| 4 | +## 概述 | |
| 5 | + | |
| 6 | +重构搜索系统以支持: | |
| 7 | + | |
| 8 | +1. 外部接口友好的API响应格式(移除ES内部格式) | |
| 9 | +2. SPU维度的索引结构(包含嵌套variants数组) | |
| 10 | +3. 所有客户共用同一索引(使用tenant_id隔离) | |
| 11 | +4. 配置简化(移除MySQL相关配置,只保留ES搜索配置) | |
| 12 | +5. 创建base配置(店匠通用配置)和测试数据 | |
| 13 | + | |
| 14 | +## Phase 1: 配置文件重构 | |
| 15 | + | |
| 16 | +### 1.1 创建BASE配置文件 | |
| 17 | + | |
| 18 | +**文件**: [`config/schema/base/config.yaml`](config/schema/base/config.yaml) (NEW) | |
| 19 | + | |
| 20 | +创建通用配置文件,所有使用店匠表的客户共用: | |
| 21 | + | |
| 22 | +- 移除 `mysql_config`, `main_table`, `extension_table` | |
| 23 | +- 移除字段配置中的 `source_table`, `source_column` | |
| 24 | +- 固定索引名称:`search_products` | |
| 25 | +- SPU级别字段定义(包含嵌套variants) | |
| 26 | +- 必需字段:`tenant_id` (KEYWORD, required) | |
| 27 | +- 扁平化价格字段:`min_price`, `max_price`, `compare_at_price` | |
| 28 | +- 多语言字段:`title_zh`, `title_en`, `description_zh`, `description_en` 等 | |
| 29 | +- 嵌套variants结构定义 | |
| 30 | + | |
| 31 | +**注意**:店匠的店铺都使用base配置,不需要单独配置。允许其他深度定制客户(如customer1)有自己的配置。 | |
| 32 | + | |
| 33 | +### 1.2 更新配置加载器 | |
| 34 | + | |
| 35 | +**文件**: [`config/config_loader.py`](config/config_loader.py) | |
| 36 | + | |
| 37 | +修改: | |
| 38 | + | |
| 39 | +- 移除 `mysql_config`, `main_table`, `extension_table` 解析(设为可选,向后兼容) | |
| 40 | +- 移除字段配置中的 `source_table`, `source_column` 解析(设为可选) | |
| 41 | +- 支持固定 `es_index_name` 为 `search_products`(base配置) | |
| 42 | +- 添加 `tenant_id` 字段验证(必需字段) | |
| 43 | +- 支持嵌套字段配置(variants) | |
| 44 | + | |
| 45 | +### 1.3 更新字段类型定义 | |
| 46 | + | |
| 47 | +**文件**: [`config/field_types.py`](config/field_types.py) | |
| 48 | + | |
| 49 | +修改: | |
| 50 | + | |
| 51 | +- `FieldConfig` 中的 `source_table`, `source_column` 设为可选(向后兼容) | |
| 52 | +- 确保嵌套字段支持(nested fields)正常工作 | |
| 53 | +- 添加扁平化价格字段类型支持 | |
| 54 | + | |
| 55 | +## Phase 2: 索引结构重构(SPU维度) | |
| 56 | + | |
| 57 | +### 2.1 更新Mapping生成器 | |
| 58 | + | |
| 59 | +**文件**: [`indexer/mapping_generator.py`](indexer/mapping_generator.py) | |
| 60 | + | |
| 61 | +修改: | |
| 62 | + | |
| 63 | +- 生成SPU级别的mapping | |
| 64 | +- 添加 `tenant_id` 字段(KEYWORD, required) | |
| 65 | +- 添加嵌套 `variants` 字段(nested type) | |
| 66 | +- 添加扁平化价格字段(`min_price`, `max_price`, `compare_at_price`) | |
| 67 | +- 支持SPU级别字段映射 | |
| 68 | + | |
| 69 | +### 2.2 创建SPU数据转换器 | |
| 70 | + | |
| 71 | +**文件**: [`indexer/spu_transformer.py`](indexer/spu_transformer.py) (NEW) | |
| 72 | + | |
| 73 | +创建SPU数据转换器: | |
| 74 | + | |
| 75 | +- 从MySQL读取SPU和SKU数据(`shoplazza_product_spu` 和 `shoplazza_product_sku` 表) | |
| 76 | +- 按SPU聚合SKU数据为variants数组 | |
| 77 | +- 计算扁平化价格字段(min_price, max_price, compare_at_price) | |
| 78 | +- 生成SPU级别的ES文档 | |
| 79 | +- 注入 `tenant_id` 字段 | |
| 80 | + | |
| 81 | +### 2.3 创建店匠数据导入脚本 | |
| 82 | + | |
| 83 | +**文件**: [`scripts/ingest_shoplazza.py`](scripts/ingest_shoplazza.py) (NEW) | |
| 84 | + | |
| 85 | +创建店匠数据导入脚本: | |
| 86 | + | |
| 87 | +- 从MySQL读取 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 88 | +- 按 `spu_id` 和 `tenant_id` 关联数据 | |
| 89 | +- 使用SPU转换器转换数据 | |
| 90 | +- 批量导入到ES索引 `search_products` | |
| 91 | +- 支持 `--tenant-id` 参数 | |
| 92 | + | |
| 93 | +## Phase 3: API响应格式重构 | |
| 94 | + | |
| 95 | +### 3.1 更新响应模型 | |
| 96 | + | |
| 97 | +**文件**: [`api/models.py`](api/models.py) | |
| 98 | + | |
| 99 | +修改 `SearchResponse` 模型: | |
| 100 | + | |
| 101 | +- 将 `hits` 改为 `results` (List[ProductResult]) | |
| 102 | +- 添加 `ProductResult` 模型(包含product_id, title, variants, relevance_score等) | |
| 103 | +- 添加 `VariantResult` 模型(包含variant_id, title, price, sku等) | |
| 104 | +- 保持 `facets` 格式 | |
| 105 | +- 添加 `suggestions` 和 `related_searches` 字段(暂时返回空数组) | |
| 106 | + | |
| 107 | +### 3.2 创建结果转换器 | |
| 108 | + | |
| 109 | +**文件**: [`api/result_formatter.py`](api/result_formatter.py) (NEW) | |
| 110 | + | |
| 111 | +创建结果格式化器: | |
| 112 | + | |
| 113 | +- 将ES返回的 `_hits` 格式转换为外部接口格式 | |
| 114 | +- 提取SPU级别字段 | |
| 115 | +- 提取嵌套variants数组 | |
| 116 | +- 计算 `relevance_score`(从 `_score` 转换,归一化到0-1) | |
| 117 | +- 格式化facets结果 | |
| 118 | +- 生成suggestions和related_searches(暂时返回空数组) | |
| 119 | + | |
| 120 | +### 3.3 更新搜索器 | |
| 121 | + | |
| 122 | +**文件**: [`search/searcher.py`](search/searcher.py) | |
| 123 | + | |
| 124 | +修改: | |
| 125 | + | |
| 126 | +- 在搜索查询中添加 `tenant_id` 过滤(必需,从请求参数或配置获取) | |
| 127 | +- 更新结果处理逻辑,使用结果格式化器 | |
| 128 | +- 移除ES内部格式字段(`_id`, `_score`, `_source`) | |
| 129 | +- 返回格式化的外部接口格式 | |
| 130 | + | |
| 131 | +### 3.4 更新API路由 | |
| 132 | + | |
| 133 | +**文件**: [`api/routes/search.py`](api/routes/search.py) | |
| 134 | + | |
| 135 | +修改: | |
| 136 | + | |
| 137 | +- 添加 `tenant_id` 参数(从请求头 `X-Tenant-ID` 或查询参数 `tenant_id` 获取) | |
| 138 | +- 在搜索请求中添加 `tenant_id` 过滤 | |
| 139 | +- 使用结果格式化器格式化响应 | |
| 140 | +- 返回新的响应格式 | |
| 141 | + | |
| 142 | +## Phase 4: 测试数据生成 | |
| 143 | + | |
| 144 | +### 4.1 创建测试数据生成脚本 | |
| 145 | + | |
| 146 | +**文件**: [`scripts/generate_test_data.py`](scripts/generate_test_data.py) (NEW) | |
| 147 | + | |
| 148 | +创建测试数据生成脚本: | |
| 149 | + | |
| 150 | +- 生成100条SPU测试数据 | |
| 151 | +- 为每个SPU生成1-5个SKU变体 | |
| 152 | +- 包含中文和英文标题 | |
| 153 | +- 包含价格、库存、图片等字段 | |
| 154 | +- 输出为MySQL INSERT语句或CSV文件 | |
| 155 | + | |
| 156 | +### 4.2 创建数据导入脚本 | |
| 157 | + | |
| 158 | +**文件**: [`scripts/import_test_data.py`](scripts/import_test_data.py) (NEW) | |
| 159 | + | |
| 160 | +创建数据导入脚本: | |
| 161 | + | |
| 162 | +- 连接MySQL数据库 | |
| 163 | +- 导入测试数据到 `shoplazza_product_spu` 和 `shoplazza_product_sku` 表 | |
| 164 | +- 设置 `tenant_id` 为base客户的ID(如 "base" 或 "1") | |
| 165 | +- 验证数据导入结果 | |
| 166 | + | |
| 167 | +## Phase 5: 测试脚本和文档 | |
| 168 | + | |
| 169 | +### 5.1 创建测试脚本 | |
| 170 | + | |
| 171 | +**文件**: [`scripts/test_base.py`](scripts/test_base.py) (NEW) | |
| 172 | + | |
| 173 | +创建base配置测试脚本: | |
| 174 | + | |
| 175 | +- 测试数据导入 | |
| 176 | +- 测试搜索API | |
| 177 | +- 测试多语言搜索 | |
| 178 | +- 测试facets聚合 | |
| 179 | +- 验证响应格式(results格式,非_hits格式) | |
| 180 | +- 验证tenant_id过滤 | |
| 181 | + | |
| 182 | +### 5.2 创建说明文档 | |
| 183 | + | |
| 184 | +**文件**: [`docs/BASE_CONFIG_GUIDE.md`](docs/BASE_CONFIG_GUIDE.md) (NEW) | |
| 185 | + | |
| 186 | +创建base配置测试指南: | |
| 187 | + | |
| 188 | +- 数据导入步骤 | |
| 189 | +- 配置说明 | |
| 190 | +- API测试示例 | |
| 191 | +- 常见问题解答 | |
| 192 | + | |
| 193 | +## Phase 6: 更新设计文档 | |
| 194 | + | |
| 195 | +### 6.1 更新设计文档 | |
| 196 | + | |
| 197 | +**文件**: [`设计文档.md`](设计文档.md) | |
| 198 | + | |
| 199 | +修改: | |
| 200 | + | |
| 201 | +- 更新索引结构说明(SPU维度,所有客户共用 `search_products` 索引) | |
| 202 | +- 更新配置说明(移除MySQL相关配置,只保留ES搜索配置) | |
| 203 | +- 更新API响应格式说明(results格式,非_hits格式) | |
| 204 | +- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息) | |
| 205 | +- 添加base配置说明 | |
| 206 | + | |
| 207 | +## 关键修改点 | |
| 208 | + | |
| 209 | +1. **索引结构**: | |
| 210 | + | |
| 211 | +- 索引名称:`search_products`(所有客户共用) | |
| 212 | +- 索引粒度:SPU级别 | |
| 213 | +- 租户隔离:使用 `tenant_id` 字段过滤 | |
| 214 | +- 嵌套结构:`variants` 数组包含SKU数据 | |
| 215 | + | |
| 216 | +2. **配置简化**: | |
| 217 | + | |
| 218 | +- 移除 `mysql_config`, `main_table`, `extension_table`(设为可选,向后兼容) | |
| 219 | +- 移除字段配置中的 `source_table`, `source_column`(设为可选) | |
| 220 | +- 只保留ES搜索相关配置 | |
| 221 | + | |
| 222 | +3. **API响应格式**: | |
| 223 | + | |
| 224 | +- 从 `_hits`, `_source`, `_score` 改为 `results`, `product_id`, `title`, `relevance_score` | |
| 225 | +- 添加 `variants` 数组 | |
| 226 | +- 添加 `suggestions` 和 `related_searches`(暂时返回空数组) | |
| 227 | + | |
| 228 | +4. **数据导入**: | |
| 229 | + | |
| 230 | +- 从MySQL读取SPU和SKU数据(Pipeline层决定) | |
| 231 | +- 按SPU聚合SKU数据 | |
| 232 | +- 生成SPU级别的ES文档 | |
| 233 | +- 注入 `tenant_id` 字段 | |
| 234 | + | |
| 235 | +5. **配置架构**: | |
| 236 | + | |
| 237 | +- 配置文件只包含搜索引擎关注的内容 | |
| 238 | +- 数据来源由Pipeline层(脚本/工具)决定 | |
| 239 | +- 转换器类型由Pipeline选择,不由配置决定 | |
| 240 | +- 配置文件不引入mysql到ES层次的东西 | |
| 241 | + | |
| 242 | +### To-dos | |
| 243 | + | |
| 244 | +- [ ] Create ResponseTransformer to convert ES hits to Shoplazza format (results, facets, suggestions, related_searches) | |
| 245 | +- [ ] Update API models: add VariantOption, ProductVariant, ProductResult, update SearchResponse with new format | |
| 246 | +- [ ] Update search route to use ResponseTransformer and return Shoplazza format | |
| 247 | +- [ ] Create script to generate 100 SPU+SKU test records for customer2 in Shoplazza tables | |
| 248 | +- [ ] Create customer2 config.yaml with search-only fields (no pipeline details) | |
| 249 | +- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure | |
| 250 | +- [ ] Create customer2 ingestion script that loads from MySQL and uses SPU transformer | |
| 251 | +- [ ] Create test script and documentation for customer2 setup and testing | |
| 252 | +- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions | |
| 0 | 253 | \ No newline at end of file | ... | ... |