# API响应格式优化与SPU索引重构

## 概述

重构搜索系统以支持：

1. 外部接口友好的API响应格式（移除ES内部格式）
2. SPU维度的索引结构（包含嵌套variants数组）
3. 所有客户共用同一索引（使用tenant_id隔离）
4. 配置简化（移除MySQL相关配置，只保留ES搜索配置）
5. 添加新客户（tenant2）测试数据和配置

## 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配置。
但是允许有其他某个深度定制客户有自己的索引，比如当前有一套索引tenant1，我们不用动他，他的数据灌入流程是另外一份，写死的，他的索引配置也是另外一份。也就是我们的搜索服务可以支持多种配置，索引结构变了、字段变了，就是多一分配置，只是店匠多数用户都用base配置即可。
下面，如果有用到 tenant2 的，应该就是指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` 为tenant2的ID
- 验证数据导入结果

## Phase 5: 测试脚本和文档

### 5.1 创建测试脚本

**文件**: [`scripts/test_tenant2.py`](scripts/test_tenant2.py) (NEW)

创建tenant2测试脚本：

- 测试数据导入
- 测试搜索API
- 测试多语言搜索
- 测试facets聚合
- 验证响应格式

### 5.2 创建说明文档

**文件**: [`docs/TENANT2_TEST_GUIDE.md`](docs/TENANT2_TEST_GUIDE.md) (NEW)

创建tenant2测试指南：

- 数据导入步骤
- 配置说明
- API测试示例
- 常见问题解答

## Phase 6: 更新设计文档

### 6.1 更新设计文档

**文件**: [`设计文档.md`](设计文档.md)

修改：

- 更新索引结构说明（SPU维度，所有客户共用）
- 更新配置说明（移除MySQL相关配置）
- 更新API响应格式说明
- 更新数据导入流程说明
- 添加tenant2测试说明

## 关键修改点

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` 字段