<!-- 2bec2252-690d-478e-9ce8-bc9073ec23ae c3f51467-b81b-47b7-869f-3da700299e26 -->
API响应格式优化与SPU索引重构
概述
重构搜索系统以实现:
- 外部接口友好的API响应格式(移除ES内部格式
_hits,_source,_score) - SPU维度的索引结构(包含嵌套variants数组)
- 所有客户共用同一索引(使用tenant_id隔离)
- 配置简化(完全移除MySQL相关配置,只保留ES搜索配置)
- 创建base配置(店匠通用配置)和SPU数据导入流程
核心设计原则
- 配置只关注ES搜索:配置文件只包含ES字段定义、查询域、排序规则等搜索相关配置
- 数据灌入流程写死:数据来源和转换逻辑由Pipeline层(脚本)决定,不在配置中体现
- 代码简洁无冗余:不做向后兼容,直接删除不需要的代码
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级别字段定义:
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相关字段
文件: <code>config/config_loader.py</code>
修改:
- 删除
TenantConfig中的mysql_config,main_table,extension_table字段定义 - 删除
_parse_config中解析这些字段的代码 - 删除
_parse_field_config中解析source_table,source_column的代码 - 保持其他配置解析逻辑不变
文件: <code>config/field_types.py</code>
修改:
- 删除
FieldConfig中的source_table,source_column字段定义 - 保持其他字段类型定义不变
1.3 更新配置验证
文件: <code>config/config_loader.py</code>
修改:
- 添加
tenant_id字段验证(必需字段) - 移除所有与MySQL/数据源相关的验证逻辑
Phase 2: 索引结构重构(SPU维度)
2.1 更新Mapping生成器
文件: <code>indexer/mapping_generator.py</code>
修改:
- 在
_generate_mappings中: - 添加
tenant_id字段(KEYWORD, required) - 支持嵌套
variants字段(nested type) - 支持扁平化价格字段(
min_price,max_price,compare_at_price) - 确保所有字段映射正确生成
2.2 创建SPU数据转换器
文件: <code>indexer/spu_transformer.py</code> (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 创建店匠数据导入脚本
文件: <code>scripts/ingest_shoplazza.py</code> (NEW)
创建店匠数据导入脚本:
- 连接MySQL数据库(连接信息通过参数或环境变量传入)
- 读取
shoplazza_product_spu和shoplazza_product_sku表 - 使用SPU转换器转换数据
- 批量导入到ES索引
search_products - 支持
--tenant-id参数(必需) - 支持
--recreate参数(重建索引) - 支持
--batch-size参数
Phase 3: API响应格式重构
3.1 更新响应模型
文件: <code>api/models.py</code>
修改:
- 创建
VariantResult模型: variant_id,title,price,sku,stock,options等- 创建
ProductResult模型: product_id,title,handle,description,vendor,product_type,tagsprice,compare_at_price,currency,image_url,in_stockvariants(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 创建结果格式化器
文件: <code>api/result_formatter.py</code> (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 更新搜索器
文件: <code>search/searcher.py</code>
修改:
- 添加
tenant_id参数到search方法(必需) - 修改 查询构建:在filter中添加
tenant_id过滤(必需) - 修改 结果处理:
- 使用
ResultFormatter格式化结果 - 返回
results而不是hits - 移除ES内部格式字段(
_id,_score,_source) - 修改
SearchResult类: - 将
hits改为results(List[ProductResult]) - 添加
suggestions和related_searches字段
3.4 更新API路由
文件: <code>api/routes/search.py</code>
修改:
- 添加
tenant_id参数获取: - 优先从请求头
X-Tenant-ID获取 - 其次从查询参数
tenant_id获取 - 如果都没有,返回400错误
- 修改 搜索调用:
- 传递
tenant_id给searcher.search() - 修改 响应构建:
- 使用格式化后的
results - 添加
suggestions和related_searches(暂时返回空数组)
Phase 4: DataTransformer重构
4.1 重构DataTransformer(向后兼容,用于tenant1)
文件: <code>indexer/data_transformer.py</code>
修改:
- 保持 现有逻辑(用于tenant1等旧配置)
- 添加 检查:如果
field.source_column不存在,跳过该字段(向后兼容) - 注意:base配置不使用DataTransformer,使用SPU转换器
Phase 5: 测试数据生成
5.1 创建测试数据生成脚本
文件: <code>scripts/generate_test_data.py</code> (NEW)
创建测试数据生成脚本:
- 生成100条SPU测试数据(符合
shoplazza_product_spu表结构) - 为每个SPU生成1-5个SKU变体(符合
shoplazza_product_sku表结构) - 包含中文和英文标题
- 包含价格、库存、图片等字段
- 输出为MySQL INSERT语句或CSV文件
- 设置
tenant_id为指定值
5.2 创建数据导入脚本
文件: <code>scripts/import_test_data.py</code> (NEW)
创建数据导入脚本:
- 连接MySQL数据库
- 导入测试数据到
shoplazza_product_spu和shoplazza_product_sku表 - 设置
tenant_id为base客户的ID(如 "base" 或 "1") - 验证数据导入结果
Phase 6: 测试脚本和文档
6.1 创建测试脚本
文件: <code>scripts/test_base.py</code> (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 创建说明文档
文件: <code>docs/BASE_CONFIG_GUIDE.md</code> (NEW)
创建base配置测试指南:
- 数据导入步骤
- 配置说明(强调不包含MySQL配置)
- API测试示例(包含tenant_id参数)
- 响应格式说明
- 常见问题解答
Phase 7: 更新设计文档
7.1 更新设计文档
修改:
- 更新索引结构说明(SPU维度,所有客户共用
search_products索引) - 更新配置说明(完全移除MySQL相关配置,只保留ES搜索配置)
- 更新API响应格式说明(results格式,非hits格式)
- 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息)
- 添加base配置说明
- 添加tenant_id隔离说明
关键修改点总结
- 配置系统:
- 完全移除
mysql_config,main_table,extension_table,source_table,source_column - 配置只包含ES搜索相关配置
- 代码简洁,无冗余,无向后兼容逻辑
- 数据转换:
- SPU转换器直接从MySQL读取,不依赖配置
- 数据映射逻辑写死在代码中
- 支持嵌套variants数组
- 索引结构:
- SPU级别索引
- 嵌套variants字段
- tenant_id字段(必需)
- API响应:
- 从
hits改为results - 从
_id,_score,_source改为product_id,relevance_score, 结构化字段 - 包含
variants数组
- 租户隔离:
- 所有客户共用
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 tenant2 in Shoplazza tables
- [ ] Create tenant2 config.yaml with search-only fields (no pipeline details)
- [ ] Create or update SPUDataTransformer to join SPU+SKU and create nested variants structure
- [ ] Create tenant2 ingestion script that loads from MySQL and uses SPU transformer
- [ ] Create test script and documentation for tenant2 setup and testing
- [ ] Update design document: SPU-level indexing, unified index, config separation, pipeline decisions