API响应格式优化与SPU索引重构
概述
重构搜索系统以支持:
- 外部接口友好的API响应格式(移除ES内部格式)
- SPU维度的索引结构(包含嵌套variants数组)
- 所有客户共用同一索引(使用tenant_id隔离)
- 配置简化(移除MySQL相关配置,只保留ES搜索配置)
- 添加新客户(customer2)测试数据和配置
Phase 1: 配置文件重构
1.1 创建BASE配置文件
文件: <code>config/schema/base/config.yaml</code> (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 更新配置加载器
文件: <code>config/config_loader.py</code>
修改:
- 移除
mysql_config,main_table,extension_table解析 - 移除字段配置中的
source_table,source_column解析 - 固定
es_index_name为search_products - 添加
tenant_id字段验证(必需字段) - 支持嵌套字段配置(variants)
1.4 更新字段类型定义
文件: <code>config/field_types.py</code>
修改:
- 移除
FieldConfig中的source_table,source_column - 添加嵌套字段支持(nested fields)
- 添加扁平化价格字段类型
Phase 2: 索引结构重构(SPU维度)
2.1 更新Mapping生成器
文件: <code>indexer/mapping_generator.py</code>
修改:
- 生成SPU级别的mapping
- 添加
tenant_id字段(KEYWORD, required) - 添加嵌套
variants字段(nested type) - 添加扁平化价格字段(
min_price,max_price,compare_at_price) - 移除SKU级别的字段映射
2.2 创建SPU数据转换器
文件: <code>indexer/spu_transformer.py</code> (NEW)
创建SPU数据转换器:
- 从MySQL读取SPU和SKU数据
- 按SPU聚合SKU数据为variants数组
- 计算扁平化价格字段(min_price, max_price, compare_at_price)
- 生成SPU级别的ES文档
- 注入
tenant_id字段
2.3 更新数据导入脚本
文件: <code>scripts/ingest_shoplazza.py</code> (NEW)
创建店匠数据导入脚本:
- 从MySQL读取
shoplazza_product_spu和shoplazza_product_sku表 - 按
spu_id和tenant_id关联数据 - 使用SPU转换器转换数据
- 批量导入到ES索引
search_products - 支持
--tenant-id参数
Phase 3: API响应格式重构
3.1 更新响应模型
文件: <code>api/models.py</code>
修改 SearchResponse 模型:
- 将
hits改为results(List[ProductResult]) - 添加
ProductResult模型(包含product_id, title, variants, relevance_score等) - 添加
VariantResult模型(包含variant_id, title, price, sku等) - 保持
facets格式 - 添加
suggestions和related_searches字段(暂时返回空数组)
3.2 创建结果转换器
文件: <code>api/result_formatter.py</code> (NEW)
创建结果格式化器:
- 将ES返回的
_hits格式转换为外部接口格式 - 提取SPU级别字段
- 提取嵌套variants数组
- 计算
relevance_score(从_score转换) - 格式化facets结果
- 生成suggestions和related_searches(暂时返回空数组)
3.3 更新搜索器
文件: <code>search/searcher.py</code>
修改:
- 在搜索查询中添加
tenant_id过滤(必需) - 更新结果处理逻辑,使用结果格式化器
- 移除ES内部格式字段(
_id,_score,_source) - 返回格式化的外部接口格式
3.4 更新API路由
文件: <code>api/routes/search.py</code>
修改:
- 添加
tenant_id参数(从请求头或查询参数获取) - 在搜索请求中添加
tenant_id过滤 - 使用结果格式化器格式化响应
- 返回新的响应格式
Phase 4: 测试数据生成
4.1 创建测试数据生成脚本
文件: <code>scripts/generate_test_data.py</code> (NEW)
创建测试数据生成脚本:
- 生成100条SPU测试数据
- 为每个SPU生成1-5个SKU变体
- 包含中文和英文标题
- 包含价格、库存、图片等字段
- 输出为MySQL INSERT语句或CSV文件
4.2 创建数据导入脚本
文件: <code>scripts/import_test_data.py</code> (NEW)
创建数据导入脚本:
- 连接MySQL数据库
- 导入测试数据到
shoplazza_product_spu和shoplazza_product_sku表 - 设置
tenant_id为customer2的ID - 验证数据导入结果
Phase 5: 测试脚本和文档
5.1 创建测试脚本
文件: <code>scripts/test_customer2.py</code> (NEW)
创建customer2测试脚本:
- 测试数据导入
- 测试搜索API
- 测试多语言搜索
- 测试facets聚合
- 验证响应格式
5.2 创建说明文档
文件: <code>docs/CUSTOMER2_TEST_GUIDE.md</code> (NEW)
创建customer2测试指南:
- 数据导入步骤
- 配置说明
- API测试示例
- 常见问题解答
Phase 6: 更新设计文档
6.1 更新设计文档
修改:
- 更新索引结构说明(SPU维度,所有客户共用)
- 更新配置说明(移除MySQL相关配置)
- 更新API响应格式说明
- 更新数据导入流程说明
- 添加customer2测试说明
关键修改点
- 索引结构:
- 索引名称:
search_products(所有客户共用) - 索引粒度:SPU级别
- 租户隔离:使用
tenant_id字段过滤 - 嵌套结构:
variants数组包含SKU数据
- 配置简化:
- 移除
mysql_config,main_table,extension_table - 移除字段配置中的
source_table,source_column - 只保留ES搜索相关配置
- API响应格式:
- 从
_hits,_source,_score改为results,product_id,title,relevance_score - 添加
variants数组 - 添加
suggestions和related_searches(暂时返回空数组)
- 数据导入:
- 从MySQL读取SPU和SKU数据
- 按SPU聚合SKU数据
- 生成SPU级别的ES文档
- 注入
tenant_id字段