# 索引字段说明文档 ## 设计思路 1. **针对店匠数据结构** - 数据源处理:时间、数值字段的规范化直接在流水线中完成,因为只有一套数据源,不需要配置化;以我们的 SPU/SKU 为标准输入。 - ES 索引方式:为了可扩展,需要定义多种索引方式,对于每个入 ES 的字段只需从中选择一种索引方式。 2. **Doc 单位为 SPU** - SKU 作为 SPU 的内部属性(ES 的 nested 结构),SKU 的价格字段展开为 `min_price`、`max_price` 作为 SPU 字段。 3. **多语言适配** - 原始数据与用户环境均为多语言,需根据语言路由到不同分析器/索引方式,在线搜索时也要考虑多语言的适配。 4. **搜索接口适配** - 接口简单,自动为多语言的数据源和 query 适配最优检索策略。 - 返回的结果格式约定为店匠系列的 SPU/SKU嵌套结构。 - 支撑 facet/过滤/排序业务需求:用户可以选择任何一个 keyword 或 HKText 类型的字段做筛选、聚合;也可以选择任何一个数值型字段做 Range 过滤或排序。 本文档详细说明了 Elasticsearch 索引中所有字段的类型、索引方式、数据来源等信息。 ## 索引基本信息 - **索引名称**: `search_products` - **索引级别**: SPU级别(商品级别) - **数据结构**: SPU文档包含嵌套的skus数组 ## 索引类型与处理说明 ### 文本字段(多语言) - **电商通用分析-中文** ```json { "type": "text", "analyzer": "hanlp_index", "search_analyzer": "hanlp_standard" } ``` - **电商通用分析-英文** ```json { "type": "text", "analyzer": "english" } ``` - **电商通用分析-日文** ```json { "type": "text", "analyzer": "japanese" } ``` - **电商通用分析-阿拉伯文** ```json { "type": "text", "analyzer": "arabic" } ``` - **电商通用分析-西班牙文** ```json { "type": "text", "analyzer": "spanish" } ``` - **电商通用分析-俄文** ```json { "type": "text", "analyzer": "russian" } ``` ### 关键词字段 - ES 输入支持字符串或字符串数组,统一写入 keyword 字段,默认大小写敏感,必要时可通过 normalizer 统一大小写。 ```json { "type": "keyword" } ``` ### Hybrid Keyword+Text(HKText)字段 - 该类型用于“精确匹配优先 + 模糊匹配兜底”的业务场景(如品牌、标签、SEO 关键词)。 - 典型 mapping: ```json { "type": "text", "analyzer": "factory_no_ngram_analyzer", "search_analyzer": "factory_no_query_analyzer", "fields": { "keyword": { "type": "keyword", "normalizer": "lowercase" } } } ``` - 业务命名:**HKText**。使用 `字段.keyword` 子字段满足过滤、聚合等精确需求,主字段支持 ngram 模糊搜索。 ### 数值字段 - **整数**:`{ "type": "long" }` - **浮点数**:`{ "type": "float" }` ### 日期字段 - 预处理:统一转换为 ISO8601(UTC)字符串或毫秒时间戳;空值保持 null。 - ES mapping: ```json { "type": "date", "format": "strict_date_optional_time||epoch_millis" } ``` - 查询:支持范围检索、排序与聚合。 ### 文本-多语言向量化 - 调用“文本向量化”模块生成 1024 维向量,适用于标题、描述等语义检索场景。 ```json { "type": "dense_vector", "dims": 1024, "index": true, "similarity": "dot_product" } ``` ### 图片-向量化 - 调用“图片向量化”模块生成 1024 维向量,并保留图片 URL 以便回显。 ```json { "type": "nested", "properties": { "vector": { "type": "dense_vector", "dims": 1024, "similarity": "dot_product" }, "url": { "type": "text" } } } ``` ## 字段说明表 ### 基础字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-------------|------| | tenant_id | KEYWORD | 是 | SPU表 | tenant_id | BIGINT | BIGINT转字符串 | 租户ID,用于多租户隔离 | | spu_id | KEYWORD | 是 | SPU表 | id | BIGINT | BIGINT转字符串 | SPU ID(主键) | | handle | KEYWORD | 是 | SPU表 | handle | VARCHAR(255) | | 商品URL handle | 数据预处理列留空表示该字段无需额外处理。 ### 文本搜索字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | Boost权重 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-----------|-------------|------| | title | TEXT | 是 | SPU表 | title | VARCHAR(512) | 3.0 | | 商品标题,权重最高 | | brief | TEXT | 是 | SPU表 | brief | VARCHAR(512) | 1.5 | | 商品简介 | | description | TEXT | 是 | SPU表 | description | TEXT | 1.0 | | 商品详细描述 | ### SEO字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | Boost权重 | 是否返回 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-----------|---------|-------------|------| | seo_title | TEXT | 是 | SPU表 | seo_title | VARCHAR(512) | 2.0 | 否 | | SEO标题,用于提升相关性 | | seo_description | TEXT | 是 | SPU表 | seo_description | TEXT | 1.5 | 否 | | SEO描述 | | seo_keywords | HKText | 是 | SPU表 | seo_keywords | VARCHAR(1024) | 2.0 | 否 | 按逗号分割为list,去除空白项 | SEO关键词,支持模糊匹配+精确过滤 | ### 分类和标签字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | Boost权重 | 是否返回 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-----------|---------|-------------|------| | vendor | HKText | 是 | SPU表 | vendor | VARCHAR(255) | 1.5 | 是 | | 供应商/品牌,HKText字段自动提供 `vendor.keyword` 用于过滤、聚合 | | tags | HKText | 是 | SPU表 | tags | VARCHAR(1024) | 1.0 | 是 | | 标签字段,支持模糊搜索;使用 `tags.keyword` 进行精确过滤 | | category | HKText | 是 | SPU表 | category | VARCHAR(255) | 1.5 | 是 | | 类目字段,使用 `category.keyword` 进行过滤/分面 | ### 价格字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-------------|------| | min_price | FLOAT | 是 | SKU表(聚合计算) | price | DECIMAL(10,2) | 聚合所有SKU最小值并转FLOAT | 最低价格(从所有SKU中取最小值) | | max_price | FLOAT | 是 | SKU表(聚合计算) | price | DECIMAL(10,2) | 聚合所有SKU最大值并转FLOAT | 最高价格(从所有SKU中取最大值) | | compare_at_price | FLOAT | 是 | SKU表(聚合计算) | compare_at_price | DECIMAL(10,2) | 聚合所有SKU最大值并转FLOAT | 原价(从所有SKU中取最大值) | **价格计算逻辑**: - `min_price`: 取该SPU下所有SKU的price字段的最小值 - `max_price`: 取该SPU下所有SKU的price字段的最大值 - `compare_at_price`: 取该SPU下所有SKU的compare_at_price字段的最大值(如果存在) ### 图片字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-------------|------| | image_url | KEYWORD | 否 | SPU表 | image_src | VARCHAR(500) | 补全协议/域名,确保绝对URL | 商品主图URL,仅用于展示 | ### 文本嵌入字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-------------|------| | title_embedding | TEXT_EMBEDDING | 是 | 计算生成 | title | VARCHAR(512) | BGE-M3模型生成1024维向量 | 标题的文本向量(1024维),用于语义搜索 | **说明**: - 向量维度:1024 - 相似度算法:dot_product(点积) - 数据来源:基于title字段通过BGE-M3模型生成 ### 时间字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 是否返回 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|---------|-------------|------| | create_time | DATE | 是 | SPU表 | create_time | DATETIME | 是 | 转换为UTC ISO8601字符串 | 创建时间 | | update_time | DATE | 是 | SPU表 | update_time | DATETIME | 是 | 转换为UTC ISO8601字符串 | 更新时间 | | shoplazza_created_at | DATE | 是 | SPU表 | shoplazza_created_at | DATETIME | 否 | 转换为UTC ISO8601字符串 | 店匠系统创建时间 | | shoplazza_updated_at | DATE | 是 | SPU表 | shoplazza_updated_at | DATETIME | 否 | 转换为UTC ISO8601字符串 | 店匠系统更新时间 | ### 嵌套SKUs字段(SKU级别) | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-------------|------| | skus | JSON (nested) | 是 | SKU表 | - | - | 汇总同SPU下SKU记录,构建nested数组 | SKU数组(嵌套结构) | #### SKUs子字段 | 索引字段名 | ES字段类型 | 是否索引 | 数据来源表 | 表中字段名 | 表中字段类型 | 数据预处理 | 说明 | |-----------|-----------|---------|-----------|-----------|-------------|-------------|------| | skus.sku_id | keyword | 是 | SKU表 | id | BIGINT | BIGINT转字符串 | SKU ID | | skus.title | text | 是 | SKU表 | title | VARCHAR(500) | | SKU标题 | | skus.price | float | 是 | SKU表 | price | DECIMAL(10,2) | DECIMAL转FLOAT | SKU价格 | | skus.compare_at_price | float | 是 | SKU表 | compare_at_price | DECIMAL(10,2) | DECIMAL转FLOAT | 原价 | | skus.sku | keyword | 是 | SKU表 | sku | VARCHAR(100) | | SKU编码 | | skus.stock | long | 是 | SKU表 | inventory_quantity | INT(11) | INT转LONG | 库存数量 | | skus.options | object | 是 | SKU表 | option1/option2/option3 | VARCHAR(255) | 合并option1/2/3并去除空值 | 选项(颜色、尺寸等) | **Variants结构说明**: - `variants` 是一个嵌套对象数组,每个元素代表一个SKU - 使用ES的nested类型,支持对嵌套字段进行独立查询和过滤 - `options` 对象包含 `option1`、`option2`、`option3` 三个字段,分别对应SKU表中的选项值 ## 字段类型说明 ### ES字段类型映射 | ES字段类型 | Elasticsearch映射 | 用途 | |-----------|------------------|------| | KEYWORD | keyword | 精确匹配、过滤、聚合、排序 | | TEXT | text | 全文检索(支持分词) | | HKText | text + keyword子字段 | 精确优先的模糊/过滤混合场景 | | FLOAT | float | 浮点数(价格、权重等) | | LONG | long | 整数(库存、计数等) | | DATE | date | 日期时间 | | TEXT_EMBEDDING | dense_vector | 文本向量(1024维) | | IMAGE_VECTOR | nested+dense_vector | 图片语义检索(含URL) | | JSON | object/nested | 嵌套对象 | ### 分析器说明 | 分析器名称 | 语言 | 说明 | |-----------|------|------| | chinese_ecommerce | 中文 | Ansj中文分词器(电商优化),用于中文文本的分词和搜索 | ## 索引配置 ### 索引设置 - **分片数**: 1 - **副本数**: 0 - **刷新间隔**: 30秒 ### 查询域(Query Domains) 系统定义了多个查询域,用于在不同场景下搜索不同的字段组合: 1. **default(默认索引)**: 搜索所有文本字段 - 包含字段:title, brief, description, seo_title, seo_description, seo_keywords, vendor, product_type, tags, category - Boost: 1.0 2. **title(标题索引)**: 仅搜索标题相关字段 - 包含字段:title, seo_title - Boost: 2.0 3. **vendor(品牌索引)**: 仅搜索品牌字段 - 包含字段:vendor - Boost: 1.5 4. **category(类目索引)**: 仅搜索类目字段 - 包含字段:category - Boost: 1.5 5. **tags(标签索引)**: 搜索标签和SEO关键词 - 包含字段:tags, seo_keywords - Boost: 1.0 ## 数据转换规则 ### 数据类型转换 1. **BIGINT → KEYWORD**: 数字ID转换为字符串(如 `spu_id`, `sku_id`) 2. **DECIMAL → FLOAT**: 价格字段从DECIMAL转换为FLOAT 3. **INT → LONG**: 库存数量从INT转换为LONG 4. **DATETIME → DATE**: 时间字段转换为ISO格式字符串 ### 特殊处理 1. **价格聚合**: 从多个SKU的价格中计算min_price、max_price、compare_at_price 2. **图片URL处理**: 如果image_src不是完整URL,会自动添加协议前缀 3. **选项合并**: 将SKU表的option1、option2、option3合并为options对象 ## 注意事项 1. **多租户隔离**: 所有查询必须包含 `tenant_id` 过滤条件 2. **嵌套查询**: 查询variants字段时需要使用nested查询语法 3. **字段命名**: 用于过滤的字段应使用 `*_keyword` 后缀的字段 4. **向量搜索**: title_embedding字段用于语义搜索,需要配合文本查询使用 5. **Boost权重**: 不同字段的boost权重影响搜索结果的相关性排序 ## 数据来源表结构 ### SPU表(shoplazza_product_spu) 主要字段: - `id`: BIGINT - 主键ID - `tenant_id`: BIGINT - 租户ID - `handle`: VARCHAR(255) - URL handle - `title`: VARCHAR(512) - 商品标题 - `brief`: VARCHAR(512) - 商品简介 - `description`: TEXT - 商品描述 - `vendor`: VARCHAR(255) - 供应商/品牌 - `category`: VARCHAR(255) - 类目 - `tags`: VARCHAR(1024) - 标签 - `seo_title`: VARCHAR(512) - SEO标题 - `seo_description`: TEXT - SEO描述 - `seo_keywords`: VARCHAR(1024) - SEO关键词 - `image_src`: VARCHAR(500) - 图片URL - `create_time`: DATETIME - 创建时间 - `update_time`: DATETIME - 更新时间 - `shoplazza_created_at`: DATETIME - 店匠创建时间 - `shoplazza_updated_at`: DATETIME - 店匠更新时间 spu表全部字段 "Field" "Type" "Null" "Key" "Default" "Extra" "id" "bigint(20)" "NO" "PRI" "auto_increment" "shop_id" "bigint(20)" "NO" "MUL" "" "shoplazza_id" "varchar(64)" "NO" "" "" "handle" "varchar(255)" "YES" "MUL" "" "title" "varchar(500)" "NO" "" "" "brief" "varchar(1000)" "YES" "" "" "description" "text" "YES" "" "" "spu" "varchar(100)" "YES" "" "" "vendor" "varchar(255)" "YES" "" "" "vendor_url" "varchar(500)" "YES" "" "" "seo_title" "varchar(500)" "YES" "" "" "seo_description" "text" "YES" "" "" "seo_keywords" "text" "YES" "" "" "image_src" "varchar(500)" "YES" "" "" "image_width" "int(11)" "YES" "" "" "image_height" "int(11)" "YES" "" "" "image_path" "varchar(255)" "YES" "" "" "image_alt" "varchar(500)" "YES" "" "" "inventory_policy" "varchar(50)" "YES" "" "" "inventory_quantity" "int(11)" "YES" "" "0" "" "inventory_tracking" "tinyint(1)" "YES" "" "0" "" "published" "tinyint(1)" "YES" "" "0" "" "published_at" "datetime" "YES" "MUL" "" "requires_shipping" "tinyint(1)" "YES" "" "1" "" "taxable" "tinyint(1)" "YES" "" "0" "" "fake_sales" "int(11)" "YES" "" "0" "" "display_fake_sales" "tinyint(1)" "YES" "" "0" "" "mixed_wholesale" "tinyint(1)" "YES" "" "0" "" "need_variant_image" "tinyint(1)" "YES" "" "0" "" "has_only_default_variant" "tinyint(1)" "YES" "" "0" "" "tags" "text" "YES" "" "" "note" "text" "YES" "" "" "category" "varchar(255)" "YES" "" "" "shoplazza_created_at" "datetime" "YES" "" "" "shoplazza_updated_at" "datetime" "YES" "MUL" "" "tenant_id" "bigint(20)" "NO" "MUL" "" "creator" "varchar(64)" "YES" "" "" "" "create_time" "datetime" "NO" "" "CURRENT_TIMESTAMP" "" "updater" "varchar(64)" "YES" "" "" "" "update_time" "datetime" "NO" "" "CURRENT_TIMESTAMP" "on update CURRENT_TIMESTAMP" "deleted" "bit(1)" "NO" "" "b'0'" "" ### SKU表(shoplazza_product_sku) 主要字段: - `id`: BIGINT - 主键ID(对应variant_id) - `spu_id`: BIGINT - SPU ID(关联字段) - `title`: VARCHAR(500) - 变体标题 - `price`: DECIMAL(10,2) - 价格 - `compare_at_price`: DECIMAL(10,2) - 原价 - `sku`: VARCHAR(100) - SKU编码 - `inventory_quantity`: INT(11) - 库存数量 - `option1`: VARCHAR(255) - 选项1 - `option2`: VARCHAR(255) - 选项2 - `option3`: VARCHAR(255) - 选项3 sku全部字段 "Field" "Type" "Null" "Key" "Default" "Extra" "id" "bigint(20)" "NO" "PRI" "auto_increment" "spu_id" "bigint(20)" "NO" "MUL" "" "shop_id" "bigint(20)" "NO" "MUL" "" "shoplazza_id" "varchar(64)" "NO" "" "" "shoplazza_product_id" "varchar(64)" "NO" "MUL" "" "shoplazza_image_id" "varchar(64)" "YES" "" "" "title" "varchar(500)" "YES" "" "" "sku" "varchar(100)" "YES" "MUL" "" "barcode" "varchar(100)" "YES" "" "" "position" "int(11)" "YES" "" "0" "" "price" "decimal(10,2)" "YES" "" "" "compare_at_price" "decimal(10,2)" "YES" "" "" "cost_price" "decimal(10,2)" "YES" "" "" "option1" "varchar(255)" "YES" "" "" "option2" "varchar(255)" "YES" "" "" "option3" "varchar(255)" "YES" "" "" "inventory_quantity" "int(11)" "YES" "" "0" "" "weight" "decimal(10,2)" "YES" "" "" "weight_unit" "varchar(10)" "YES" "" "" "image_src" "varchar(500)" "YES" "" "" "wholesale_price" "json" "YES" "" "" "note" "text" "YES" "" "" "extend" "json" "YES" "" "" "shoplazza_created_at" "datetime" "YES" "" "" "shoplazza_updated_at" "datetime" "YES" "" "" "tenant_id" "bigint(20)" "NO" "MUL" "" "creator" "varchar(64)" "YES" "" "" "" "create_time" "datetime" "NO" "" "CURRENT_TIMESTAMP" "" "updater" "varchar(64)" "YES" "" "" "" "update_time" "datetime" "NO" "" "CURRENT_TIMESTAMP" "on update CURRENT_TIMESTAMP" "deleted" "bit(1)" "NO" "" "b'0'" "" ## TODO 多语言问题。 店匠的products接口返回的 title tags note category seo_title seo_description 等字段,为商家销售区域所使用语言,因此英文为主,各种语言都有。 不同语言需要用不同的分析器,需要拆分不同的字段。 考虑的方法是: 1. 索引层面: 每种文本字段,都设置多份语言索引,暂时先包括 zh en 两种即可。 以下字段做两份,如果以后对接的商家达到8种语言,那么这些字段也对应的扩展到8份。 title brief description seo_title seo_description seo_keywords vendor vendor_keyword product_type product_type_keyword category 2. tenant - 数据灌入: 对每个tenant设置一一个语言,作为tenant的一个基本配置。 写入索引的时候,根据语言配置将title 等文本字段写入对应的索引字段(比如 title_en) 查询的时候,将query转为商家所用语言,并到对应的field去查。 3. 在线搜索时: 多语言搜索作为效果优化的高级特性,比如某个用户配置了 zh, en 两种语言,那么 如索引的时候会进行不全,入两个字段。 搜索的时候 也准备 query_en query_zh 两个查询词 分别到多个字段搜索。