在电商系统中,套餐商品(如“手机+耳机+保护壳”组合)和 SPU 自动聚合逻辑 是提升商品展示效率、优化搜索体验的关键能力。本文将为你提供一套完整的 Elasticsearch 套餐商品建模 + SPU 自动聚合逻辑 的详细设计方案,涵盖数据结构、索引设计、聚合规则、同步机制与搜索集成。
一、业务场景
1. 套餐商品(Bundle Product)
- 由多个独立商品(SKU)组合而成,打包销售。
- 示例:
“iPhone 15 Pro 套餐:手机 + AirPods + 保护壳,立减 500 元”
2. SPU 自动聚合
- 多个相似商品(如不同颜色/容量的 iPhone 15)应自动聚合成一个 SPU 展示。
- 避免搜索结果中重复出现同一商品的不同规格。
二、核心目标
| 目标 | 说明 |
|---|
| ✅ 统一展示 | 套餐和单品都能在搜索中合理呈现 |
| ✅ 智能聚合 | 相似商品自动合并为 SPU |
| ✅ 灵活配置 | 支持手动指定聚合规则或排除 |
| ✅ 高性能搜索 | 聚合结果可被高效查询、排序、过滤 |
| ✅ 数据一致性 | 聚合结果与源 SKU 实时同步 |
三、数据建模设计
1. 商品类型分类
| 类型 | 说明 | Elasticsearch 映射 |
|---|
| 单品 SKU | 独立可售商品 | product_type: "sku" |
| 虚拟 SPU | 聚合多个 SKU 的逻辑商品 | product_type: "spu" |
| 套餐 Bundle | 多个商品组合销售 | product_type: "bundle" |
2. 统一商品索引设计(推荐单索引)
PUT /product-catalog-2024-10
{
"settings": { ... },
"mappings": {
"dynamic": false,
"properties": {
"id": { "type": "keyword" },
"title": { "type": "text", "analyzer": "ik_max_word" },
"product_type": {
"type": "keyword",
"index": true
},
"brand": { "type": "keyword" },
"category_path": { "type": "keyword" },
"tags": { "type": "keyword" },
"price": { "type": "scaled_float", "scaling_factor": 100 },
"original_price": { "type": "scaled_float", "scaling_factor": 100 },
"stock_status": { "type": "keyword" },
"spu_id": { "type": "keyword" },
"is_master": { "type": "boolean" },
"spu_title": { "type": "text" },
"bundle_items": {
"type": "nested",
"properties": {
"sku_id": { "type": "keyword" },
"title": { "type": "text" },
"quantity": { "type": "integer" },
"image": { "type": "keyword" }
}
},
"bundle_savings": { "type": "scaled_float", "scaling_factor": 100 },
"specifications": {
"type": "nested",
"properties": {
"name": { "type": "keyword" },
"value": { "type": "keyword" }
}
},
"sales_count": { "type": "long" },
"rating": { "type": "float" }
}
}
}
四、SPU 自动聚合逻辑
1. 聚合策略(基于规则)
| 规则 | 说明 |
|---|
| 品牌 + 类目 + 核心属性匹配 | 如“Apple + 手机 + 型号=iPhone 15” → 聚合 |
| 标题语义相似度 | 使用 NLP 或向量模型判断标题相似性 |
| 排除特定属性 | 忽略“颜色”、“容量”等可变属性 |
| 手动配置白名单/黑名单 | 某些商品不参与聚合 |
2. 聚合字段选择(用于匹配)
[
"brand",
"category_path",
"specifications.name:型号",
"specifications.name:系列"
]
示例:
- iPhone 15 Pro 黑色 256GB
- iPhone 15 Pro 白色 512GB
→ 共同点:brand=Apple, category=手机, 型号=iPhone 15 Pro → 属于同一 SPU
3. SPU ID 生成规则
spu_{brand}_{model}_{series}
→ spu_Apple_iPhone_15_Pro
或使用哈希:
spu_id = md5("Apple:iPhone 15 Pro")
4. 聚合流程(自动化)
5. SPU 汇总文档生成逻辑
当一组 SKU 被聚合为 SPU 时,生成一条 product_type: "spu" 的虚拟文档:
{
"id": "spu_Apple_iPhone_15_Pro",
"product_type": "spu",
"spu_title": "Apple iPhone 15 Pro",
"brand": "Apple",
"category_path": "手机",
"price_min": 799900,
"price_max": 999900,
"stock_status": "in_stock",
"sales_count": 12500,
"rating": 4.9,
"image": "https://.../iphone15pro.jpg",
"spec_summary": "颜色: 白,黑,蓝; 容量: 256GB,512GB,1TB",
"sku_count": 6
}
✅ 该文档用于搜索展示,不参与下单。
五、套餐商品建模
1. 套餐创建方式
| 方式 | 说明 |
|---|
| 手动创建 | 运营后台配置套餐商品 |
| 自动推荐 | 基于关联规则(如“常一起购买”)生成套餐建议 |
| 促销活动绑定 | 大促期间临时组合 |
2. 套餐文档示例
{
"id": "bundle_1001",
"product_type": "bundle",
"title": "iPhone 15 Pro 超值套餐",
"bundle_items": [
{
"sku_id": "sku_phone_001",
"title": "iPhone 15 Pro 256GB",
"quantity": 1,
"image": "phone.jpg"
},
{
"sku_id": "sku_airpods_001",
"title": "AirPods 4",
"quantity": 1,
"image": "airpods.jpg"
},
{
"sku_id": "sku_case_001",
"title": "官方保护壳",
"quantity": 1,
"image": "case.jpg"
}
],
"price": 949900,
"original_price": 1049700,
"bundle_savings": 99800,
"stock_status": "in_stock",
"tags": ["限时优惠", "套装专享"],
"sales_count": 800
}
六、搜索集成设计
1. 搜索时混合返回:SPU + Bundle + 单品(可选)
GET /product-catalog/_search
{
"query": {
"multi_match": {
"query": "iPhone 15",
"fields": ["title^3", "spu_title", "bundle_items.title"]
}
},
"post_filter": {
"term": { "stock_status": "in_stock" }
},
"aggs": {
"by_type": {
"terms": { "field": "product_type" }
}
},
"sort": [
{ "sales_count": "desc" }
]
}
2. 前端展示策略
| 类型 | 展示方式 |
|---|
spu | 商品卡片,显示价格区间、规格摘要 |
bundle | 特殊角标“套餐”,显示节省金额 |
sku | 仅在详情页或筛选后展示 |
七、数据同步与更新机制
1. 触发条件
- 新增/更新 SKU
- 套餐创建/修改
- 商品下架/库存变更
2. 同步方式(事件驱动)
MySQL (SKU Table)
→ Debezium/CDC
→ Kafka
→ Aggregation Service
→ 更新 SPU 文档
→ 更新 Bundle 文档
→ Bulk 更新 ES
3. 更新策略
- 使用
bulk API 批量更新相关文档。 - 设置
refresh=wait_for 保证搜索实时可见。 - 支持手动触发“全量重建 SPU”。
八、性能优化建议
| 优化点 | 方案 |
|---|
| 减少 nested 查询 | 将常用规格冗余为 color, capacity 等独立字段 |
| 缓存聚合结果 | Redis 缓存 SPU 映射关系(TTL=5min) |
| 分页优化 | 使用 search_after 替代 from+size |
| 字段裁剪 | _source 过滤非必要字段 |
九、管理后台支持
1. 聚合规则配置
- 支持添加/删除聚合维度(如“型号”、“系列”)
- 支持排除某些 SKU 不参与聚合
2. 手动干预
- 强制将某 SKU 划入指定 SPU
- 拆分 SPU
- 置顶某个 SKU 作为主图
十、总结:完整架构图
+------------------+ +---------------------+
| MySQL (SKU/BUNDLE)| --> | Kafka (Change Event)|
+------------------+ +----------+----------+
|
v
+--------------------------+
| Aggregation Service |
| - SPU 自动聚合 |
| - Bundle 文档生成 |
+------------+-------------+
|
v
+--------------------------+
| Elasticsearch Cluster |
| Index: product-catalog-* |
| Documents: |
| - SKU (product_type=sku)|
| - SPU (virtual) |
| - Bundle |
+------------+-------------+
|
v
+--------------------------+
| App / Search Frontend |
| 混合展示 SPU + Bundle |
+--------------------------+
十一、扩展建议
| 场景 | 建议方案 |
|---|
| 向量聚类 | 使用 dense_vector + kNN 聚类自动发现相似商品 |
| 动态套餐 | 用户选择商品后,实时推荐搭配套餐 |
| SPU 版本管理 | 记录 SPU 聚合历史,支持回滚 |
| AB 测试 | 对比“聚合 vs 不聚合”的转化率 |