# Option值参与搜索功能文档 ## 功能概述 实现了让子SKU的option值(option1_value, option2_value, option3_value)参与搜索的功能。 **新架构说明**:基于简洁版配置架构,索引结构由 `mappings/search_products.json` 定义,搜索行为由 `config/config.yaml` 配置。 ## 改动清单 ### 1. 索引Mapping (`mappings/search_products.json`) 添加3个新字段用于存储去重后的option值: ```json { "mappings": { "properties": { "option1_values": { "type": "keyword" }, "option2_values": { "type": "keyword" }, "option3_values": { "type": "keyword" } } } } ``` ### 2. 配置文件 (`config/config.yaml`) #### 新增字段权重配置 ```yaml # 字段权重配置 field_boosts: # ... 其他字段 ... option1_values: 0.5 option2_values: 0.5 option3_values: 0.5 ``` #### 将新字段加入搜索域 ```yaml indexes: - name: "default" label: "默认搜索" fields: - "title_zh" - "brief_zh" # ... 其他字段 ... - "option1_values" - "option2_values" - "option3_values" boost: 1.0 ``` #### 新增SPU配置项 ```yaml spu_config: enabled: true spu_field: "spu_id" inner_hits_size: 10 # 配置哪些option维度参与检索(进索引、以及在线搜索) # 格式为list,选择option1/option2/option3中的一个或多个 searchable_option_dimensions: ['option1', 'option2', 'option3'] ``` ### 3. 配置加载器 (`config/config_loader.py`) #### SPUConfig类扩展 ```python @dataclass class SPUConfig: enabled: bool = False spu_field: Optional[str] = None inner_hits_size: int = 3 searchable_option_dimensions: List[str] = field( default_factory=lambda: ['option1', 'option2', 'option3'] ) ``` #### 配置解析逻辑 ```python spu_config = SPUConfig( enabled=spu_data.get("enabled", False), spu_field=spu_data.get("spu_field"), inner_hits_size=spu_data.get("inner_hits_size", 3), searchable_option_dimensions=spu_data.get( "searchable_option_dimensions", ['option1', 'option2', 'option3'] ) ) ``` ### 4. 数据灌入模块 (`indexer/spu_transformer.py`) #### 加载配置 ```python def __init__(self, db_engine: Any, tenant_id: str): self.db_engine = db_engine self.tenant_id = tenant_id # 加载配置获取searchable_option_dimensions try: config_loader = ConfigLoader() config = config_loader.load_config() self.searchable_option_dimensions = config.spu_config.searchable_option_dimensions except Exception as e: print(f"Warning: Failed to load config, using default: {e}") self.searchable_option_dimensions = ['option1', 'option2', 'option3'] ``` #### 提取option值逻辑 ```python # 从子SKU提取option值 option1_values = [] option2_values = [] option3_values = [] for _, sku_row in skus.iterrows(): if pd.notna(sku_row.get('option1')): option1_values.append(str(sku_row['option1'])) if pd.notna(sku_row.get('option2')): option2_values.append(str(sku_row['option2'])) if pd.notna(sku_row.get('option3')): option3_values.append(str(sku_row['option3'])) # 去重并根据配置决定是否写入索引 if 'option1' in self.searchable_option_dimensions: doc['option1_values'] = list(set(option1_values)) if option1_values else [] else: doc['option1_values'] = [] # option2和option3类似... ``` ### 5. 在线搜索 **无需修改代码**! 现有的 `get_match_fields_for_index` 机制会自动: - 从 `field_boosts` 读取字段权重 - 将配置中的字段加入multi_match的fields - 应用配置的权重(0.5) ## 使用说明 ### 配置方式 在 `config/config.yaml` 中修改 `searchable_option_dimensions`: ```yaml # 所有option都参与检索 searchable_option_dimensions: ['option1', 'option2', 'option3'] # 只有option1参与检索 searchable_option_dimensions: ['option1'] # option1和option3参与检索 searchable_option_dimensions: ['option1', 'option3'] ``` ### 权重调整 在 `config/config.yaml` 的 `field_boosts` 中修改: ```yaml field_boosts: option1_values: 0.8 # 调整为0.8 option2_values: 0.5 option3_values: 0.5 ``` ### 数据灌入流程 #### 方案1:完整重建索引 ```bash python scripts/recreate_and_import.py \ --tenant-id 1 \ --recreate \ --db-host localhost \ --db-database saas \ --db-username root \ --db-password xxx ``` #### 方案2:单独灌入数据 ```bash python scripts/ingest_shoplazza.py \ --tenant-id 1 \ --db-host localhost \ --db-database saas \ --db-username root \ --db-password xxx ``` **注意**:如果修改了mapping(添加新字段),需要先重建索引。 ### 测试验证 #### 1. 验证数据是否正确写入 使用ES查询检查文档: ```bash curl -X GET "localhost:9200/search_products/_search?pretty" \ -H 'Content-Type: application/json' -d' { "query": {"match_all": {}}, "size": 1, "_source": ["spu_id", "title_zh", "option1_values", "option2_values", "option3_values"] } ' ``` **期望结果**: ```json { "hits": { "hits": [ { "_source": { "spu_id": "123", "title_zh": "测试商品", "option1_values": ["红色", "蓝色", "绿色"], "option2_values": ["S", "M", "L"], "option3_values": [] } } ] } } ``` #### 2. 验证option值参与搜索 假设某个商品有子SKU的option1值为 "红色"、"蓝色": ```bash # 搜索"红色"应该能匹配到该商品 curl -X POST "localhost:9200/search_products/_search?pretty" \ -H 'Content-Type: application/json' -d' { "query": { "multi_match": { "query": "红色", "fields": ["title_zh^3.0", "option1_values^0.5"] } } } ' ``` #### 3. 通过API测试 ```bash curl -X POST "http://localhost:6002/api/search" \ -H "Content-Type: application/json" \ -d '{ "query": "红色", "tenant_id": "1", "size": 10 }' ``` **期望**:搜索"红色"能匹配到option1_value包含"红色"的商品。 ## 设计亮点 ### 1. 配置驱动 通过配置文件灵活控制哪些option参与检索,无需修改代码: ```yaml searchable_option_dimensions: ['option1'] # 配置即可 ``` ### 2. 权重集中管理 所有字段权重统一在 `field_boosts` 中配置,便于调整: ```yaml field_boosts: title_zh: 3.0 option1_values: 0.5 # 集中管理,一目了然 ``` ### 3. 复用现有框架 充分利用现有的 `get_match_fields_for_index` 机制: - 自动从 `field_boosts` 读取权重 - 自动将字段加入搜索 - 无需额外开发 ### 4. 最小改动 只修改了必要的模块: - ✅ 添加mapping字段 - ✅ 添加配置项 - ✅ 修改数据灌入逻辑 - ❌ 无需修改搜索逻辑(自动支持) ### 5. 向后兼容 默认配置包含所有option,不影响现有功能: ```yaml searchable_option_dimensions: ['option1', 'option2', 'option3'] # 默认全部 ``` ## 架构优势 ### 简洁版配置架构 本功能基于新的简洁版配置架构实现: | 组件 | 职责 | 优势 | |------|------|------| | `mappings/search_products.json` | 定义索引结构 | 单一真相来源 | | `config/config.yaml` | 定义搜索行为 | 简洁易读 | | `field_boosts` | 字段权重字典 | 集中管理 | ### 与旧架构对比 **旧架构**:需要在 `config.yaml` 中详细定义字段类型、analyzer等。 **新架构**:只需配置权重,字段结构由mapping定义。 ```yaml # 新架构 - 只配置权重 field_boosts: option1_values: 0.5 ``` vs ```yaml # 旧架构 - 需要详细定义(已废弃) fields: - name: "option1_values" type: "KEYWORD" boost: 0.5 index: true store: true # ... 更多配置 ``` ## 注意事项 ### 1. 索引重建 修改mapping后需要重建索引: ```bash python scripts/recreate_and_import.py --tenant-id 1 --recreate --db-xxx ``` ### 2. 配置验证 修改配置后建议验证: ```python from config import ConfigLoader loader = ConfigLoader() config = loader.load_config(validate=True) # 自动验证 ``` ### 3. 权重调优 初始权重设为0.5,可根据实际效果调整: ```yaml field_boosts: option1_values: 0.8 # 提高权重 option2_values: 0.3 # 降低权重 ``` ### 4. 空值处理 未配置的option字段会写入空数组,不影响搜索: ```python # 如果只配置 ['option1'] doc['option1_values'] = ["红色", "蓝色"] # 有值 doc['option2_values'] = [] # 空数组 doc['option3_values'] = [] # 空数组 ``` ## 故障排查 ### 1. option值没有进入索引 **检查项**: - ✅ `searchable_option_dimensions` 配置是否正确 - ✅ 数据灌入日志是否有警告信息 - ✅ MySQL中的SKU数据option字段是否有值 - ✅ 是否已重建索引 **解决方案**: ```bash # 查看灌入日志 python scripts/ingest_shoplazza.py --tenant-id 1 --db-xxx # 检查配置 python -c "from config import ConfigLoader; print(ConfigLoader().load_config().spu_config.searchable_option_dimensions)" ``` ### 2. 搜索option值没有效果 **检查项**: - ✅ 字段是否在 `default` 索引域的 `fields` 列表中 - ✅ 权重是否设置正确(不为0) - ✅ 使用ES的 `_analyze` API 检查分词 **解决方案**: ```yaml # 确保字段在搜索域中 indexes: - name: "default" fields: - "option1_values" # 必须包含 # 确保权重合理 field_boosts: option1_values: 0.5 # 不要设为0 ``` ### 3. 配置加载失败 **检查项**: - ✅ `config/config.yaml` 语法是否正确 - ✅ 查看应用启动日志 **解决方案**: ```bash # 验证YAML语法 python -c "import yaml; yaml.safe_load(open('config/config.yaml'))" # 测试配置加载 python -c "from config import ConfigLoader; ConfigLoader().load_config()" ``` ## 性能影响 ### 索引大小 每个SPU增加3个keyword数组字段,预估增加: - 小数据集(<10k SPU):可忽略 - 中数据集(10k-100k SPU):约5-10% - 大数据集(>100k SPU):需要监控 ### 搜索性能 - option_values字段为keyword类型,精确匹配,性能良好 - 权重设为0.5,对相关性影响较小 - 建议监控查询延迟并根据实际情况调整 ## 扩展建议 ### 1. 动态权重 未来可支持根据用户行为动态调整权重: ```yaml field_boosts: option1_values: ${dynamic.option1_weight} # 动态权重 ``` ### 2. 多语言option 支持option值的多语言搜索: ```yaml field_boosts: option1_values_zh: 0.5 option1_values_en: 0.5 ``` ### 3. option分组 支持按option分组聚合: ```yaml facets: - field: "option1_values" type: "terms" ``` --- **功能版本**: v1.0 **文档日期**: 2024-12-02 **架构版本**: v2.0 (简洁版配置架构)