SPU-SKU索引方案选型
spu为单位。SKU字段展开作为SPU属性 1.1 索引方案 除了title, brielf description seo相关 cate tags vendor所有影响相关性的字段都在spu。 sku只有款式、价格、重量、库存等相关属性。所以,可以以spu为单位建立索引。 sku中需要参与搜索的属性(比如价格、库存)展开到spu。 sku的所有需要返回的字段作为nested字段,仅用于返回。 灌入数据准备 def build_product_document(product, skus):
提取价格列表(转换为float,保留两位小数)
price_list = [float(sku.price) for sku in skus if sku.price is not None]
提取重量信息(重量转为int,单位统一为克;重量+单位拼接为字符串)
weight_list = [int(float(sku.weight) * 1000) for sku in skus if sku.weight is not None] # 转为整数克 weight_with_unit_list = [f"{sku.weight}{sku.weight_unit}" for sku in skus if sku.weight and sku.weight_unit]
计算库存总和
total_stock = sum([sku.inventory_quantity for sku in skus if sku.inventory_quantity is not None])
计算价格区间
min_price = min(price_list) if price_list else 0.0 max_price = max(price_list) if price_list else 0.0
return { "spu_id": str(product.id), "title": product.title,
# SPU级别的选项名称定义(如:颜色、尺码、材质) "option1_name": getattr(product, 'option1', None), "option2_name": getattr(product, 'option2', None), "option3_name": getattr(product, 'option3', None), # SKU搜索字段(展开) # 价格(int)、重量(int)、重量单位拼接重量(keyword),都以list形式灌入 "sku_prices": price_list, # 所有SKU价格列表,用于范围聚合 "sku_weights": weight_list, # 重量数值列表(转换为整数克) "sku_weight_units": weight_with_unit_list, # 重量+单位字符串列表 # 库存总和 将SKU的库存加起来作为一个值灌入 "total_inventory": total_stock, # SKU库存总和 # 售价,灌入3个字段:SKU价格列表、最高价、最低价 "min_price": min_price, # 最低售价 "max_price": max_price, # 最高售价 "price_range": { # 价格区间对象,便于范围查询 "gte": min_price, "lte": max_price }, # SKU详细信息(nested结构,仅用于返回) "skus": [ { "sku_id": str(sku.id), "price": float(sku.price) if sku.price else 0.0, "compare_at_price": float(sku.compare_at_price) if sku.compare_at_price else None, "sku_code": sku.sku, "stock": sku.inventory_quantity, "weight": float(sku.weight) if sku.weight else None, "weight_unit": sku.weight_unit, # SKU级别的选项值(对应SPU的选项名称) "option1_value": sku.option1, "option2_value": sku.option2, "option3_value": sku.option3, "image_src": sku.image_src } for sku in skus ], # 其他SPU级别字段(根据索引文档补充) "tenant_id": str(product.tenant_id), "brief": product.brief, "description": product.description, "vendor": product.vendor, "category": product.category, "tags": product.tags.split(',') if product.tags else [], "seo_title": product.seo_title, "seo_description": product.seo_description, "seo_keywords": product.seo_keywords.split(',') if product.seo_keywords else [], "image_url": product.image_src, "create_time": product.create_time.isoformat() if product.create_time else None, "update_time": product.update_time.isoformat() if product.update_time else None} 索引定义 { "mappings": { "properties": { "tenant_id": { "type": "keyword" }, "spu_id": { "type": "keyword" }, // 文本相关性相关字段 "title_zh": { "type": "text", "analyzer": "hanlp_index", "search_analyzer": "hanlp_standard" }, "brief_zh": { "type": "text", "analyzer": "hanlp_index", "search_analyzer": "hanlp_standard" }, "description_zh": { "type": "text", "analyzer": "hanlp_index", "search_analyzer": "hanlp_standard" }, "vendor_zh": { "type": "text", "analyzer": "hanlp_index", "search_analyzer": "hanlp_standard", "fields": { "keyword": { "type": "keyword", "normalizer": "lowercase" } } },
"title_en": { "type": "text", "analyzer": "english", "search_analyzer": "english", }, "brief_en": { "type": "text", "analyzer": "english", "search_analyzer": "english",
}, "description_en": { "type": "text", "analyzer": "english", "search_analyzer": "english", }, "vendor_en": { "type": "text", "analyzer": "english", "search_analyzer": "english", "fields": { "keyword": { "type": "keyword", "normalizer": "lowercase" } } },
"tags": { "type": "keyword", },
"min_price": { "type": "float" }, "max_price": { "type": "float" }, "compare_at_price": { "type": "float" }, "sku_prices": { "type": "float" }, "sku_weights": { "type": "long" }, "sku_weight_units": { "type": "keyword" }, "total_inventory": { "type": "long" },
"image_url": { "type": "keyword", "index": false },
"title_embedding": { "type": "dense_vector", "dims": 1024, "index": true, "similarity": "dot_product" },
"create_time": { "type": "date" }, "update_time": { "type": "date" },
"option1_name": { "type": "keyword" }, "option2_name": { "type": "keyword" }, "option3_name": { "type": "keyword" },
"skus": { "type": "nested", "properties": { "sku_id": { "type": "keyword" }, "price": { "type": "float" }, "compare_at_price": { "type": "float" }, "sku_code": { "type": "keyword" }, "stock": { "type": "long" }, "weight": { "type": "float" }, "weight_unit": { "type": "keyword" }, "option1_value": { "type": "keyword" }, "option2_value": { "type": "keyword" }, "option3_value": { "type": "keyword" }, "image_src": { "type": "keyword", "index": false } } } } } } 1.2 查询方案 对数组字段使用 dis_max,只取最高分,避免累加。 其他重点字段
Sku title
category 2.1 Mysql 在spu表中: Field Type category varchar(255) category_id bigint(20) category_google_id bigint(20) category_level int(11) category_path varchar(500) 2.2 ES索引 2.2.1 输入数据 设计 1,2,3级分类 三个字段,的 category (原始文本) 2.2.2 索引方法 设计要求:
- 支持facet(精确过滤、keyword聚合),并且性能需要足够高。
- 支持普通搜索模糊匹配(用户原始query可能包括分类词)。
- 模糊匹配要考虑多语言 方案:采用方案2
- categoryPath索引 + Prefix 查询(categoryPath.keyword: "服装/男装")(如果满足条件的key太多的则性能较差,比如 查询的是一级类目,类目树叶子节点太多时性能较差)
- categoryPath支撑模糊查询 和 多级cate keyword索引支撑精确查询。 索引阶段冗余,查询性能高。
"category_path_zh": { // 提供模糊查询功能,辅助相关性计算
"type": "text",
"analyzer": "hanlp_index",
"search_analyzer": "hanlp_standard"
},
"category_path_en": { // 提供模糊查询功能,辅助相关性计算
"type": "text",
"analyzer": "english",
"search_analyzer": "english"
},
"category_path": { // 用于多层级的筛选、精确匹配
"type": "keyword",
"normalizer": "lowercase"
}, "category_id": { "type": "keyword" }, "category_name": { "type": "keyword" }, "category_level": { "type": "integer" }, "category1_name": { // 不同层级下 可能有同名的情况,因此提供一二三级分开的查询方式 "type": "keyword" }, "category2_name": { "type": "keyword" }, "category3_name": { "type": "keyword" },
tags 3.1 数据源 多值 标签 最多输入250个标签,每个不得超过500字符,多个标签请用「英文逗号」隔开 新品,热卖,爆款 耳机,头戴式,爆款
分割后 list形式灌入 3.2 Mysql 3.3 ES索引 3.3.1 输入数据 3.3.2 索引方法
- 供应商 4.1 数据源 4.2 Mysql 4.3 ES索引 4.3.1 输入数据 4.3.2 索引方法
- 款式/选项值(options)
5.1 数据源
以下区域字段,商品属性为M(商品主体)的行需填写款式名称,商品属性为P(子款式)的行需填写款式值信息,商品属性为S(单一款式商品)的行无需填写
款式1 款式2 款式3 最多255字符 最多255字符 最多255字符 SIZE COLOR
S red
... 5.2 Mysql - API 在 SPU 的维度直接返回3个属性定义,存储在 shoplazza_product_option 中:
API在 SKU的维度直接返回3个属性值,存储在 shoplazza_product_sku 表的 option 相关的字段中: 5.3 ES索引 5.3.1 3nested,支持超过3个属性(动态)。只用作返回,不能查询。节省索引空间 "specifications": { "type": "nested", "properties": { "name": { "type": "keyword","index": false }, "value": { "type": "keyword","index": false } } },
SEO相关字段 6.1 数据源 SEO标题 SEO描述 SEO URL Handle SEO URL 重定向 SEO关键词 最多5000字符 最多5000字符 "最多支持输入255字符 (SEO URL handle只对SEO URL的「URL参数」部分进行更改,即“products/”后的内容,如:products/「URL参数」 )" "创建URL重定向,访问修改前链接可跳转到修改后的新链接页面 「Y」:TRUE 「N」:FALSE " 多个关键词请用「英文逗号」隔开
6.2 Mysql 6.3 ES索引 6.3.1 输入数据 6.3.2 索引方法