API响应格式优化与SPU索引重构.4.md 10.7 KB

<!-- 2bec2252-690d-478e-9ce8-bc9073ec23ae c3f51467-b81b-47b7-869f-3da700299e26 -->

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配置文件

文件: <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_spushoplazza_product_sku 表(写死在代码中)
  • 数据聚合:按 spu_idtenant_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_spushoplazza_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, 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 创建结果格式化器

文件: <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])
  • 添加 suggestionsrelated_searches 字段

3.4 更新API路由

文件: <code>api/routes/search.py</code>

修改:

  • 添加 tenant_id 参数获取:
  • 优先从请求头 X-Tenant-ID 获取
  • 其次从查询参数 tenant_id 获取
  • 如果都没有,返回400错误
  • 修改 搜索调用:
  • 传递 tenant_idsearcher.search()
  • 修改 响应构建:
  • 使用格式化后的 results
  • 添加 suggestionsrelated_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_spushoplazza_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 更新设计文档

文件: <code>设计文档.md</code>

修改:

  • 更新索引结构说明(SPU维度,所有客户共用 search_products 索引)
  • 更新配置说明(完全移除MySQL相关配置,只保留ES搜索配置)
  • 更新API响应格式说明(results格式,非hits格式)
  • 更新数据导入流程说明(Pipeline层决定数据源,配置不包含数据源信息)
  • 添加base配置说明
  • 添加tenant_id隔离说明

关键修改点总结

  1. 配置系统
  • 完全移除 mysql_config, main_table, extension_table, source_table, source_column
  • 配置只包含ES搜索相关配置
  • 代码简洁,无冗余,无向后兼容逻辑
  1. 数据转换
  • SPU转换器直接从MySQL读取,不依赖配置
  • 数据映射逻辑写死在代码中
  • 支持嵌套variants数组
  1. 索引结构
  • SPU级别索引
  • 嵌套variants字段
  • tenant_id字段(必需)
  1. API响应
  • hits 改为 results
  • _id, _score, _source 改为 product_id, relevance_score, 结构化字段
  • 包含 variants 数组
  1. 租户隔离
  • 所有客户共用 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