MySQL到ES字段映射说明-业务版.md
20.9 KB
MySQL 到 Elasticsearch 字段映射说明(业务版)
1. 概述
本文档说明 Elasticsearch 中的商品文档(Document)的各个字段是如何从 MySQL 数据库中的相关表获取和转换的。
1.1 数据源表
- SPU 表 (
shoplazza_product_spu): 商品基本信息 - SKU 表 (
shoplazza_product_sku): 商品变体信息(多款式) - Option 表 (
shoplazza_product_option): 选项名称定义(如:颜色、尺寸) - 类目表 (
product_category): 类目信息(通过 SPU 表的 category_id 关联)
2. 基础字段映射
2.1 标识字段
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
tenant_id |
SPU 表 | tenant_id |
直接使用,转为字符串 |
spu_id |
SPU 表 | id |
直接使用,转为字符串 |
2.2 文本字段(多语言)
文本字段支持中英文双语,根据租户配置自动翻译。
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
title.zh |
SPU 表 | title |
如果主语言是中文,直接使用;否则翻译为中文 |
title.en |
SPU 表 | title |
如果主语言是英文,直接使用;否则翻译为英文 |
brief.zh |
SPU 表 | brief |
同上 |
brief.en |
SPU 表 | brief |
同上 |
description.zh |
SPU 表 | description |
同上 |
description.en |
SPU 表 | description |
同上 |
vendor.zh |
SPU 表 | vendor |
同上 |
vendor.en |
SPU 表 | vendor |
同上 |
翻译规则:
- 根据租户配置的
primary_language确定主语言 - 如果配置了
translate_to_en=true,且主语言不是英文,则翻译为英文 - 如果配置了
translate_to_zh=true,且主语言不是中文,则翻译为中文
2.3 标签字段
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
tags |
SPU 表 | tags |
逗号分隔的字符串 → 数组示例:"标签1,标签2" → ["标签1", "标签2"] |
2.4 图片字段
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
image_url |
SPU 表 | image_src |
2.5 销量字段
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
sales |
SPU 表 | fake_sales |
转为整数,如果为空则为 0 |
2.6 时间字段
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
create_time |
SPU 表 | create_time |
转为 ISO 格式字符串(如:2024-01-01T00:00:00) |
update_time |
SPU 表 | update_time |
转为 ISO 格式字符串 |
3. 类别(Category)字段映射
3.1 类别数据来源
类别信息主要来自 SPU 表的以下字段:
category_path: 类目路径,逗号分隔的类目ID列表(如:"1,2,3")category: 类目名称(备用字段)category_id: 当前类目IDcategory_level: 类目层级
3.2 类别映射流程
步骤 1:解析 category_path
从 SPU 表的 category_path 字段解析出类目ID列表:
category_path = "1,2,3"
→ category_ids = ["1", "2", "3"]
步骤 2:ID 转名称
通过预加载的类目映射表(从 SPU 表查询 category_id 和 category 字段构建),将ID转换为名称:
映射表:{"1": "电子产品", "2": "手机", "3": "iPhone"}
category_ids = ["1", "2", "3"]
→ category_names = ["电子产品", "手机", "iPhone"]
步骤 3:构建 ES 字段
| ES 字段 | 数据来源 | 转换说明 |
|---|---|---|
category_path.zh |
类目名称列表 | 用 / 连接:"电子产品/手机/iPhone" |
category1_name |
类目名称列表[0] | 一级类目:"电子产品" |
category2_name |
类目名称列表[1] | 二级类目:"手机" |
category3_name |
类目名称列表[2] | 三级类目:"iPhone" |
category_id |
SPU 表 | category_id 转为字符串 |
category_level |
SPU 表 | category_level 转为整数 |
备用处理:
如果 category_path 为空,使用 category 字段作为备选:
- 如果
category包含/,按/分割为多级类目 - 否则,直接作为
category1_name
数据质量检查:
如果 category_path 中的类目ID在映射表中不存在,则不写入任何类目字段(视为没有类目)。
4. 多款式(SKU/Options)字段映射
4.1 SKU 嵌套结构
一个 SPU 可以有多个 SKU,每个 SKU 代表一个商品变体(如:红色-L码、蓝色-M码)。
ES 中的 skus 字段结构:
{
"skus": [
{
"sku_id": "123",
"price": 99.99,
"compare_at_price": 129.99,
"sku_code": "SKU001",
"stock": 100,
"weight": 0.5,
"weight_unit": "kg",
"option1_value": "红色",
"option2_value": "L",
"option3_value": "棉",
"image_src": "https://..."
}
]
}
4.2 SKU 字段映射
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
skus[].sku_id |
SKU 表 | id |
转为字符串 |
skus[].price |
SKU 表 | price |
转为浮点数 |
skus[].compare_at_price |
SKU 表 | compare_at_price |
转为浮点数 |
skus[].sku_code |
SKU 表 | sku |
转为字符串 |
skus[].stock |
SKU 表 | inventory_quantity |
转为整数 |
skus[].weight |
SKU 表 | weight |
转为浮点数 |
skus[].weight_unit |
SKU 表 | weight_unit |
转为字符串 |
skus[].image_src |
SKU 表 | image_src |
转为字符串 |
skus[].option1_value |
SKU 表 | option1 |
转为字符串 |
skus[].option2_value |
SKU 表 | option2 |
转为字符串 |
skus[].option3_value |
SKU 表 | option3 |
转为字符串 |
4.3 选项名称字段
选项名称来自 Option 表,按 position 字段排序(1、2、3 对应 option1、option2、option3)。
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
option1_name |
Option 表 | name (where position=1) |
第一个选项的名称(如:"颜色") |
option2_name |
Option 表 | name (where position=2) |
第二个选项的名称(如:"尺寸") |
option3_name |
Option 表 | name (where position=3) |
第三个选项的名称(如:"材质") |
查询逻辑:
SELECT position, name
FROM shoplazza_product_option
WHERE spu_id = ? AND deleted = 0
ORDER BY position
4.4 选项值字段
选项值来自所有 SKU 的 option1、option2、option3 字段,去重后形成列表。
| ES 字段 | 数据来源表 | 表中字段 | 转换说明 |
|---|---|---|---|
option1_values |
SKU 表 | option1 |
收集所有 SKU 的 option1 值,去重示例:["红色", "蓝色", "绿色"] |
option2_values |
SKU 表 | option2 |
收集所有 SKU 的 option2 值,去重示例:["S", "M", "L"] |
option3_values |
SKU 表 | option3 |
收集所有 SKU 的 option3 值,去重示例:["棉", "涤纶"] |
转换逻辑:
遍历所有 SKU:
- 收集 option1 值 → option1_values 列表
- 收集 option2 值 → option2_values 列表
- 收集 option3 值 → option3_values 列表
去重后写入 ES
注意: 只有配置在 searchable_option_dimensions 中的选项才会被索引。
4.5 规格(Specifications)字段
规格字段用于支持按规格过滤和分面搜索,将 SKU 的选项值结构化存储。
ES 中的 specifications 字段结构:
{
"specifications": [
{"sku_id": "123", "name": "颜色", "value": "红色"},
{"sku_id": "123", "name": "尺寸", "value": "L"},
{"sku_id": "124", "name": "颜色", "value": "蓝色"},
{"sku_id": "124", "name": "尺寸", "value": "M"}
]
}
构建逻辑:
从 Option 表获取选项名称映射:
position=1 → name="颜色" position=2 → name="尺寸" position=3 → name="材质"遍历所有 SKU,为每个 SKU 的每个选项值构建规格记录:
SKU.id=123, option1="红色", option2="L" → {"sku_id": "123", "name": "颜色", "value": "红色"} → {"sku_id": "123", "name": "尺寸", "value": "L"}
| ES 字段 | 数据来源 | 转换说明 |
|---|---|---|
specifications[].sku_id |
SKU 表 | id 转为字符串 |
specifications[].name |
Option 表 | name(根据 position 匹配) |
specifications[].value |
SKU 表 | option1/2/3 转为字符串 |
4.6 价格聚合字段
从所有 SKU 的价格中计算聚合值。
| ES 字段 | 数据来源 | 转换说明 |
|---|---|---|
min_price |
SKU 表 | 所有 SKU 的 price 最小值 |
max_price |
SKU 表 | 所有 SKU 的 price 最大值 |
compare_at_price |
SKU 表 | 所有 SKU 的 compare_at_price 最大值 |
sku_prices |
SKU 表 | 所有 SKU 的 price 数组示例:[99.99, 99.99, 129.99] |
计算逻辑:
遍历所有 SKU:
- 收集 price → prices 列表
- 收集 compare_at_price → compare_prices 列表
min_price = min(prices)
max_price = max(prices)
compare_at_price = max(compare_prices)
sku_prices = prices 列表
4.7 库存和重量聚合字段
| ES 字段 | 数据来源 | 转换说明 |
|---|---|---|
total_inventory |
SKU 表 | 所有 SKU 的 inventory_quantity 求和 |
sku_weights |
SKU 表 | 所有 SKU 的 weight 数组示例:[500, 500, 600] |
sku_weight_units |
SKU 表 | 所有 SKU 的 weight_unit 去重后的列表示例:["kg"] |
计算逻辑:
遍历所有 SKU:
- 累加 inventory_quantity → total_inventory
- 收集 weight → sku_weights 列表
- 收集 weight_unit → sku_weight_units 列表
total_inventory = 所有 SKU 库存之和
sku_weights = 所有 SKU 重量数组
sku_weight_units = 去重后的重量单位列表
5. 向量字段映射
5.1 标题向量(title_embedding)
| ES 字段 | 数据来源 | 转换说明 |
|---|---|---|
title_embedding |
SPU 表 title |
使用文本编码器(BGE)将标题转换为 1024 维向量优先使用 title.en,如果没有则使用 title.zh |
生成逻辑:
如果启用向量搜索:
文本 = title.en 或 title.zh
向量 = 文本编码器.encode(文本)
title_embedding = 向量(1024 维浮点数组)
6. 完整字段映射表
6.1 字段来源汇总
| ES 字段 | 数据来源表 | 表中字段 | 说明 |
|---|---|---|---|
| 基础字段 | |||
tenant_id |
SPU | tenant_id |
租户ID |
spu_id |
SPU | id |
商品ID |
title.zh/en |
SPU | title |
标题(多语言) |
brief.zh/en |
SPU | brief |
简介(多语言) |
description.zh/en |
SPU | description |
描述(多语言) |
vendor.zh/en |
SPU | vendor |
品牌(多语言) |
tags |
SPU | tags |
标签数组 |
image_url |
SPU | image_src |
主图URL |
sales |
SPU | fake_sales |
销量 |
create_time |
SPU | create_time |
创建时间 |
update_time |
SPU | update_time |
更新时间 |
| 类别字段 | |||
category_path.zh |
SPU + 类目映射 | category_path → 类目名称 |
类目路径 |
category1_name |
SPU + 类目映射 | category_path → 类目名称[0] |
一级类目 |
category2_name |
SPU + 类目映射 | category_path → 类目名称[1] |
二级类目 |
category3_name |
SPU + 类目映射 | category_path → 类目名称[2] |
三级类目 |
category_id |
SPU | category_id |
类目ID |
category_level |
SPU | category_level |
类目层级 |
| SKU 嵌套字段 | |||
skus[] |
SKU | 多个字段 | SKU 数组(见 4.2 节) |
| 选项字段 | |||
option1_name |
Option | name (position=1) |
选项1名称 |
option2_name |
Option | name (position=2) |
选项2名称 |
option3_name |
Option | name (position=3) |
选项3名称 |
option1_values |
SKU | option1 |
选项1值列表 |
option2_values |
SKU | option2 |
选项2值列表 |
option3_values |
SKU | option3 |
选项3值列表 |
| 规格字段 | |||
specifications[] |
SKU + Option | option1/2/3 + name |
规格数组 |
| 聚合字段 | |||
min_price |
SKU | price |
最低价格 |
max_price |
SKU | price |
最高价格 |
compare_at_price |
SKU | compare_at_price |
最高原价 |
sku_prices |
SKU | price |
所有价格数组 |
total_inventory |
SKU | inventory_quantity |
总库存 |
sku_weights |
SKU | weight |
所有重量数组 |
sku_weight_units |
SKU | weight_unit |
重量单位列表 |
| 向量字段 | |||
title_embedding |
SPU | title |
标题向量(1024维) |
7. 数据查询示例
7.1 查询 SPU 数据
SELECT
id, tenant_id, title, brief, description, vendor,
category, category_id, category_path, category_level,
tags, image_src, fake_sales, create_time, update_time
FROM shoplazza_product_spu
WHERE tenant_id = ? AND id = ? AND deleted = 0
7.2 查询 SKU 数据
SELECT
id, spu_id, price, compare_at_price, sku,
inventory_quantity, weight, weight_unit,
option1, option2, option3, image_src
FROM shoplazza_product_sku
WHERE tenant_id = ? AND spu_id = ? AND deleted = 0
7.3 查询 Option 数据
SELECT
position, name
FROM shoplazza_product_option
WHERE tenant_id = ? AND spu_id = ? AND deleted = 0
ORDER BY position
7.4 查询类目映射
SELECT DISTINCT
category_id, category
FROM shoplazza_product_spu
WHERE deleted = 0 AND category_id IS NOT NULL
8. ES 文档示例
GET /search_products/_search
{
"size": 1,
"_source": "*",
"query": {
"bool": {
"filter": [
{ "term": {"_id" : 74174} },
{ "term": { "tenant_id": "162" } }
]
}
}
}
结果
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0,
"hits": [
{
"_index": "search_products",
"_id": "74174",
"_score": 0,
"_source": {
"tenant_id": "162",
"spu_id": "74174",
"title.zh": "实色二阶碳纤维魔方 方形 2阶 塑料【英文包装】",
"title.en": "Solid Color 2nd Order Carbon Fiber Rubik's Cube Square 2 Steps Plastic [English Packaging",
"brief.zh": "实色二阶碳纤维魔方 方形 2阶 塑料【英文包装】",
"brief.en": "Solid Color 2nd Order Carbon Fiber Rubik's Cube Square 2 Steps Plastic [English Packaging",
"description.zh": "<p>实色二阶碳纤维魔方 方形 2阶 塑料【英文包装】</p>",
"description.en": "<p>Solid Color 2nd Order Carbon Fiber Rubik's Cube Square 2 Steps Plastic [English Packaging]</p",
"vendor.zh": "顺达",
"vendor.en": "Shunda",
"title_embedding": [
-0.005125104915350676,
...
0.018752742558717728
],
"tags": [
"魔方",
"ShunDa"
],
"category_path.zh": "玩具/汽车",
"category_path.en": null,
"category1_name": "玩具",
"category2_name": "汽车",
"category_name_text.zh": "汽车",
"category_name_text.en": null,
"category_name": "汽车",
"category_id": "593389466647880832",
"category_level": 2,
"option1_name": "color",
"option2_name": "size",
"option3_name": "material",
"image_url": "////img.staticdj.com/6eb4a98e2cb23af523da5456e424fc24.jpeg",
"sales": 0,
"skus": [
{
"sku_id": "3577878",
"price": 346.13,
"compare_at_price": 464.3,
"sku_code": "2210777-Orange-30-塑料英文包装",
"stock": 87,
"weight": 1.99,
"weight_unit": "kg",
"option1_value": "Orange",
"option2_value": "30",
"option3_value": "塑料英文包装"
},
{
"sku_id": "3577879",
"price": 316.62,
"compare_at_price": 466.27,
"sku_code": "2210777-Orange-8-塑料英文包装",
"stock": 41,
"weight": 1.95,
"weight_unit": "kg",
"option1_value": "Orange",
"option2_value": "8",
"option3_value": "塑料英文包装"
},
...
{
"sku_id": "3577941",
"price": 380.03,
"compare_at_price": 553.67,
"sku_code": "2210777-Olive-2-塑料英文包装",
"stock": 56,
"weight": 2.78,
"weight_unit": "kg",
"option1_value": "Olive",
"option2_value": "2",
"option3_value": "塑料英文包装"
}
],
"specifications": [
{
"sku_id": "3577878",
"name": "color",
"value": "Orange"
},
...
{
"sku_id": "3577941",
"name": "material",
"value": "塑料英文包装"
}
],
"option1_values": [
"White",
"Gold",
"Violet",
"Olive",
"Turquoise",
"Khaki",
"Teal",
"Orange"
],
"option2_values": [
"2",
"30",
"8",
"1",
"18",
"27",
"25",
"29"
],
"option3_values": [
"塑料英文包装"
],
"min_price": 262.92,
"max_price": 389.18,
"compare_at_price": 567.6,
"sku_prices": [
346.13,
...
309.64,
380.03
],
"sku_weights": [
1,
1,
...
2,
2
],
"sku_weight_units": [
"kg"
],
"total_inventory": 3269,
"create_time": "2025-11-29T00:02:00",
"update_time": "2025-12-20T00:01:41"
}
}
]
}
}
9. 关键映射关系总结
9.1 类别映射
SPU.category_path ("1,2,3")
↓ [解析ID列表]
category_ids ["1", "2", "3"]
↓ [通过映射表转换]
category_names ["电子产品", "手机", "iPhone"]
↓ [构建字段]
category_path.zh: "电子产品/手机/iPhone"
category1_name: "电子产品"
category2_name: "手机"
category3_name: "iPhone"
9.2 SKU 和选项映射
Option 表 (position=1, name="颜色")
↓
option1_name: "颜色"
SKU 表 (option1="红色", option1="蓝色")
↓ [收集所有值,去重]
option1_values: ["红色", "蓝色"]
SKU 表 + Option 表
↓ [组合构建]
specifications: [
{name: "颜色", value: "红色", sku_id: "123"},
{name: "颜色", value: "蓝色", sku_id: "124"}
]
9.3 价格聚合
SKU 表 (price: 99.99, 109.99, 129.99)
↓ [聚合计算]
min_price: 99.99
max_price: 129.99
sku_prices: [99.99, 109.99, 129.99]
附录:数据表字段对照
SPU 表主要字段
| 表字段 | ES 字段 | 说明 |
|---|---|---|
id |
spu_id |
商品ID |
tenant_id |
tenant_id |
租户ID |
title |
title.zh/en |
标题 |
brief |
brief.zh/en |
简介 |
description |
description.zh/en |
描述 |
vendor |
vendor.zh/en |
品牌 |
tags |
tags |
标签 |
category_path |
category_path.zh |
类目路径 |
category_id |
category_id |
类目ID |
category_level |
category_level |
类目层级 |
image_src |
image_url |
主图 |
fake_sales |
sales |
销量 |
create_time |
create_time |
创建时间 |
update_time |
update_time |
更新时间 |
SKU 表主要字段
| 表字段 | ES 字段 | 说明 |
|---|---|---|
id |
skus[].sku_id |
SKU ID |
price |
skus[].price, min_price, max_price, sku_prices |
价格 |
compare_at_price |
skus[].compare_at_price, compare_at_price |
原价 |
sku |
skus[].sku_code |
SKU编码 |
inventory_quantity |
skus[].stock, total_inventory |
库存 |
weight |
skus[].weight, sku_weights |
重量 |
weight_unit |
skus[].weight_unit, sku_weight_units |
重量单位 |
option1 |
skus[].option1_value, option1_values, specifications[].value |
选项1值 |
option2 |
skus[].option2_value, option2_values, specifications[].value |
选项2值 |
option3 |
skus[].option3_value, option3_values, specifications[].value |
选项3值 |
image_src |
skus[].image_src |
SKU图片 |
Option 表主要字段
| 表字段 | ES 字段 | 说明 |
|---|---|---|
position |
- | 位置(1/2/3) |
name |
option1_name, option2_name, option3_name, specifications[].name |
选项名称 |