mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1308 words
3 minutes
Elasticsearch 从 0 到 1(七):电商搜索架构实践
2025-07-12

Elasticsearch 从 0 到 1(七):电商搜索架构实践#

前六篇分别讲了:

最后这一篇,把它们串成一个完整的电商商品搜索方案。

商品搜索要解决什么问题#

一个商品搜索页通常不只是输入关键词。

它可能包含:

  • 关键词搜索;
  • 分类筛选;
  • 品牌筛选;
  • 价格区间;
  • 上架状态;
  • 销量排序;
  • 价格排序;
  • 最新排序;
  • 标题高亮;
  • 品牌聚合;
  • 分类聚合;
  • 分页;
  • 搜索词纠错和推荐。

刚开始做,不要一口吃成复杂搜索系统。

第一版可以先做:

关键词 + 分类 + 品牌 + 价格 + 排序 + 分页 + 高亮

整体架构#

一个常见架构:

用户搜索
商品搜索接口
Elasticsearch
返回商品列表
MySQL 商品数据
数据同步任务 / MQ / Binlog
Elasticsearch 商品索引

MySQL 保存真实商品数据。
ES 保存搜索文档。
搜索接口只查 ES。
下单和库存判断仍然查 MySQL 或库存系统。

商品搜索文档设计#

ES 文档要围绕搜索页设计。

示例:

{
"productId": 1001,
"title": "无线蓝牙耳机",
"subtitle": "低延迟,长续航",
"brand": "SoundGo",
"categoryId": 200,
"categoryName": "数码耳机",
"price": 199,
"sales": 3000,
"stock": 80,
"status": "ON_SALE",
"coverUrl": "https://example.com/cover.webp",
"createdAt": "2026-07-02T10:00:00"
}

文档设计原则:

  • 搜索页要展示的字段,尽量直接放进去;
  • 筛选字段用 keyword 或数值;
  • 排序字段用数值或日期;
  • 标题和描述用 text
  • 不要在搜索接口里再查一堆 MySQL 补字段。

搜索要快,文档就要适当冗余。

商品索引 Mapping#

{
"mappings": {
"properties": {
"productId": { "type": "long" },
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"fields": {
"keyword": { "type": "keyword", "ignore_above": 256 }
}
},
"subtitle": { "type": "text" },
"brand": { "type": "keyword" },
"categoryId": { "type": "long" },
"categoryName": { "type": "keyword" },
"price": { "type": "integer" },
"sales": { "type": "integer" },
"stock": { "type": "integer" },
"status": { "type": "keyword" },
"coverUrl": { "type": "keyword", "index": false },
"createdAt": { "type": "date" }
}
}
}

这里 coverUrl 只是展示,不需要搜索,所以可以关闭索引。

搜索请求设计#

public class ProductSearchRequest {
private String keyword;
private Long categoryId;
private String brand;
private Integer minPrice;
private Integer maxPrice;
private String sort;
private Integer pageNo = 1;
private Integer pageSize = 20;
}

排序建议做白名单:

default:默认相关性
sales_desc:销量倒序
price_asc:价格升序
price_desc:价格倒序
newest:最新

不要让前端直接传 ES 字段名。

搜索 DSL 组合#

{
"from": 0,
"size": 20,
"query": {
"bool": {
"must": [
{ "match": { "title": "蓝牙耳机" } }
],
"filter": [
{ "term": { "status": "ON_SALE" } },
{ "term": { "categoryId": 200 } },
{ "term": { "brand": "SoundGo" } },
{ "range": { "price": { "gte": 100, "lte": 300 } } }
]
}
},
"sort": [
{ "sales": "desc" }
],
"highlight": {
"fields": {
"title": {}
}
}
}

这就是商品搜索最核心的一段。

关键词影响相关性。
筛选条件不影响评分。
排序根据用户选择调整。
高亮用于前端展示。

筛选项怎么做#

搜索页左侧常见:

品牌
分类
价格区间

这些可以用聚合生成。

品牌聚合:

{
"size": 0,
"aggs": {
"brands": {
"terms": {
"field": "brand",
"size": 20
}
}
}
}

价格区间聚合:

{
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 100 },
{ "from": 100, "to": 300 },
{ "from": 300, "to": 500 },
{ "from": 500 }
]
}
}
}
}

聚合可以和查询条件一起用,但要注意性能,不要无脑加很多复杂聚合。

数据同步流程#

推荐流程:

商品新增 / 修改 / 上下架
更新 MySQL
写本地消息表或发送 MQ
消费者查询 MySQL 最新数据
构建 ProductDocument
写入 ES

为什么消费者要查 MySQL 最新数据?

因为消息里带的字段可能不完整,也可能已经过期。

消息只需要告诉你:

哪个商品变了
发生了什么变更

最终文档最好从 MySQL 当前状态重新构建。

上下架和库存#

商品下架后,搜索接口必须过滤:

{ "term": { "status": "ON_SALE" } }

库存字段可以展示,但不要把 ES 库存作为下单扣减依据。

因为 ES 和 MySQL 通常是最终一致,库存变化又很频繁。

下单时仍然要走真实库存系统或数据库条件更新。

搜索体验优化#

基础搜索跑通后,可以逐步优化体验:

  • 搜索高亮;
  • 搜索建议;
  • 热门搜索词;
  • 同义词;
  • 拼音搜索;
  • 品牌词识别;
  • 类目权重;
  • 销量和相关性综合排序;
  • 无结果时推荐热门商品。

不要第一版就全部做。

第一版目标应该是:

能搜到
能筛选
能排序
能分页
能高亮
数据能同步
出问题能排查

排查问题看哪里#

商品搜索出问题,一般按这个顺序排查:

  1. MySQL 里商品是否存在;
  2. ES 里文档是否存在;
  3. 文档字段是否正确;
  4. Mapping 类型是否正确;
  5. 查询 DSL 是否正确;
  6. 分词结果是否符合预期;
  7. 是否被 status、category、brand、price 过滤掉;
  8. 是否排序导致结果靠后;
  9. 同步消息是否失败;
  10. ES 查询是否超时或慢查询。

很多“搜不到”的问题,不是 ES 坏了,而是 Mapping、分词、过滤条件或数据同步出了问题。

生产注意事项#

上线前至少确认:

  • ES 不是核心交易数据源;
  • 搜索接口限制 pageSize;
  • 深分页有限制;
  • 有慢查询日志;
  • 有同步失败重试;
  • 有商品重建索引任务;
  • 有 ES 集群监控;
  • Mapping 有版本管理;
  • 索引重建有别名切换方案;
  • 下架商品不会被搜到;
  • ES 故障时有降级方案。

降级方案可以是:

  • 返回热门商品;
  • 只查 MySQL 简单列表;
  • 提示搜索服务繁忙;
  • 关闭复杂聚合。

总结#

电商搜索不是只写一条 match 查询。

完整链路包括:

  • 商品文档设计;
  • Mapping 设计;
  • DSL 查询组合;
  • Java 接口封装;
  • 高亮和分页;
  • 聚合筛选;
  • MySQL 到 ES 的数据同步;
  • 性能优化;
  • 监控和故障降级。

ES 的定位要始终清楚:

MySQL 管真实业务数据,ES 管搜索体验。

只要这个边界不乱,ES 就会成为搜索能力的放大器,而不是新的数据一致性麻烦源。

参考#

Share

If this article helped you, please share it with others!

Elasticsearch 从 0 到 1(七):电商搜索架构实践
https://mizuki.mysqil.com/posts/elasticsearch-07-ecommerce-search/
Author
梦幻晨风
Published at
2025-07-12
License
CC BY-NC-SA 4.0

Some information may be outdated

Table of Contents