# ES Mapping Configuration ## 概述 所有租户共享同一个 Elasticsearch mapping 结构。 当前目录采用“声明式 Python 规格 + 字段模板 + 最终 JSON 产物”的方式维护 `search_products` 的索引定义: - `generate_search_products_mapping.py`: 唯一的生成源,包含字段模板、语言列表、分析器配置和递归生成逻辑 - `search_products.json`: 由脚本生成的完整 ES 索引配置,包括 `settings` 和 `mappings` - `search_suggestions.json`: 搜索建议索引配置 默认应修改生成脚本中的规格定义,而不是手工编辑 `search_products.json`。 ## 字段抽象 脚本从业务语义上抽象出 4 类文本模板: - `all_language_text`: 全语言字段,不带 `keyword` - `all_language_text_with_keyword`: 全语言字段,所有受支持语言都带 `keyword` - `core_language_text`: 核心索引语言字段,不带 `keyword` - `core_language_text_with_keyword`: 核心索引语言字段,核心语言都带 `keyword` 这里的“核心索引语言”不是因为系统只支持两种语言,而是因为所有店铺、所有商品都必须至少产出这两种语言的索引内容。目前核心索引语言固定为: - `zh` - `en` “全语言”表示 mapping 为原始商品语言预留了更多语言槽位。商品实际灌入时,不要求每个字段把所有语言都填满,只要求: - 核心索引语言字段必须填充 `zh` 和 `en` - 全语言字段必须填充 `zh` 和 `en` - 如果商品原始语言属于受支持语言,还应额外填充对应的原始语言字段,例如 `ru` 当前字段大致分为几类: - 全语言字段:`title`、`keywords`、`brief`、`description`、`vendor`、`category_path`、`category_name_text` - 核心索引语言字段:`qanchors`、`enriched_tags`、`option1_values`、`option2_values`、`option3_values`、`enriched_attributes.value` - 复合嵌套字段:`image_embedding`、`specifications`、`enriched_attributes`、`skus` - 其他标量字段:`tenant_id`、`spu_id`、价格、库存、类目等 生成规则里的几个基础约束: - 中文字段使用 `index_ik`,并额外设置 `search_analyzer: query_ik` - 非中文语言使用各自的 Elasticsearch 内置 analyzer - 带 `with_keyword` 的模板会为对应语言增加 `.keyword` - `settings.analysis`、`normalizer`、`similarity` 也属于生成结果的一部分,不能只维护 `mappings.properties` ## 索引灌入指引 ### 基本原则 1. 所有商品都必须生成核心索引语言版本,也就是 `zh` 和 `en`。 2. 全语言字段除了必须有 `zh` 和 `en`,还应尽量保留商品原始语言版本。 3. 如果商品原始语言本身就是 `zh` 或 `en`,则原文直接写入对应字段,另一种核心语言通过翻译补齐。 4. 如果商品原始语言是 `ru` 这类受支持的非核心语言,则应同时写入原始语言字段和 `zh/en` 翻译结果。 5. 如果某个值为空,不应写入伪造内容;应在上游清洗后决定是否跳过该字段。 ### 核心索引语言字段 这类字段的目标是保证所有商品都至少能被中文和英文检索到。无论商品原始语言是什么,都应通过翻译或标准化得到 `zh` 和 `en` 两份结果。 典型字段: - `qanchors` - `enriched_tags` - `option1_values` - `option2_values` - `option3_values` - `enriched_attributes.value` - `specifications.value_text` 以 `category_path` 和 `option*_values` 为例,核心语言灌入结果应至少包含: - `category_path.zh` - `category_path.en` - `option1_values.zh` - `option1_values.en` - `option2_values.zh` - `option2_values.en` - `option3_values.zh` - `option3_values.en` 示例:原始商品语言为俄语,原始 `option1_values` 为 `красный, синий` ```json { "option1_values": { "zh": "红色, 蓝色", "en": "red, blue" } } ``` 示例:原始商品语言为俄语,类目路径为 `Одежда > Женская одежда > Куртки` ```json { "category_path": { "zh": "服饰 > 女装 > 夹克", "en": "Apparel > Women's Clothing > Jackets", "ru": "Одежда > Женская одежда > Куртки" } } ``` 注意:`category_path` 在 mapping 上属于全语言字段,但在灌入规范上依然要求 `zh/en` 必填。 ### 全语言字段 这类字段既要保证 `zh/en` 两个核心索引语言可用,也要尽量保留商品原始语言,以便原语种召回和更自然的检索。 典型字段: - `title` - `keywords` - `brief` - `description` - `vendor` - `category_path` - `category_name_text` 灌入规则: 1. 找到商品原始语言,例如 `ru` 2. 原文写入对应语言字段,例如 `title.ru` 3. 将原文翻译成 `zh` 和 `en` 4. 分别写入 `title.zh` 和 `title.en` 示例:原始商品语言为俄语,标题为 `Женская зимняя куртка` ```json { "title": { "zh": "女士冬季夹克", "en": "Women's winter jacket", "ru": "Женская зимняя куртка" } } ``` 示例:原始商品语言为俄语,类目名称为 `Женские куртки` ```json { "category_name_text": { "zh": "女式夹克", "en": "Women's jackets", "ru": "Женские куртки" } } ``` 示例:规格值 `specifications.value_text` / `specifications.value_keyword` ```json { "specifications": [ { "sku_id": "sku-red-s", "name": "color", "value_keyword": "красный", "value_text": { "zh": "红色", "en": "red" } } ] } ``` 其中: - `specifications.value_keyword` 保存原始规格值,用于精确过滤 / 分面 - `specifications.value_text` 保存 `zh/en` 两个核心索引语言版本,用于检索召回 ### 原始语言为中文或英文时 如果原始语言就是核心索引语言之一,不需要额外再写第三份语言字段。 示例:原始语言为中文 ```json { "title": { "zh": "女士冬季夹克", "en": "Women's winter jacket" }, "option1_values": { "zh": "红色, 蓝色", "en": "red, blue" } } ``` 示例:原始语言为英文 ```json { "title": { "zh": "女士冬季夹克", "en": "Women's winter jacket" }, "vendor": { "zh": "北境服饰", "en": "Northern Apparel" } } ``` ### 不同字段的灌入方式 可以按下面的方式理解和实现: - 标量字段:直接写固定值,例如 `tenant_id`、`spu_id`、`min_price` - 核心索引语言字段:只生成 `zh/en` - 全语言字段:生成 `zh/en`,再按原始语言补一个对应语种字段 - 嵌套字段:对每个元素内部重复应用同样规则,例如 `specifications[].value_text`、`enriched_attributes[].value` ### 推荐灌入流程 1. 识别商品原始语言 2. 提取原文标题、描述、类目、规格、属性、选项值等字段 3. 生成 `zh` 和 `en` 两份核心索引语言内容 4. 对全语言字段,如果原始语言受支持,则额外写入原始语言字段 5. 组装最终 ES 文档并写入索引 ## 生成 Mapping 在仓库根目录执行: ```bash source activate.sh python mappings/generate_search_products_mapping.py > mappings/search_products.json ``` 如果只想查看输出而不覆盖文件: ```bash source activate.sh python mappings/generate_search_products_mapping.py ``` 如果想先生成到临时文件: ```bash source activate.sh python mappings/generate_search_products_mapping.py > mappings/search_products.generated.json ``` ## 校验 Mapping 确认当前 `search_products.json` 是否与生成规则完全一致: ```bash source activate.sh python mappings/generate_search_products_mapping.py --check mappings/search_products.json ``` ## 创建索引 ```python from indexer.mapping_generator import load_mapping, create_index_if_not_exists from utils.es_client import ESClient es_client = ESClient(hosts=["http://localhost:9200"]) mapping = load_mapping() create_index_if_not_exists(es_client, "search_products", mapping) ``` ## 修改 Mapping 推荐流程: 1. 修改 `mappings/generate_search_products_mapping.py` 2. 重新生成 `mappings/search_products.json` 3. 用 `--check` 或 diff 确认变更符合预期 4. 重新创建索引并导入数据 注意:Elasticsearch 不支持直接修改已有字段的 mapping 类型,只能新增字段。如需修改字段类型,需要: 1. 删除旧索引 2. 使用新 mapping 创建索引 3. 重新导入数据 ## 字段说明 参考 `docs/索引字段说明v2-mapping结构.md`