跳到主要内容

设计搜索系统

问题

如何设计一个支持全文检索、搜索建议和高亮的搜索系统?

答案

一、整体架构

二、数据同步方案

MySQL(主数据源)

├── 方案 1:CDC(Canal + Kafka)
│ MySQL binlog → Canal → Kafka → ES Consumer
│ 优点:实时性好,对应用无侵入

├── 方案 2:双写
│ 应用同时写 MySQL 和 ES
│ 优点:简单直接
│ 缺点:一致性、代码侵入

└── 方案 3:定时全量
Schedule Job → MySQL 查询 → ES Bulk
优点:一致性最好
缺点:延迟高

推荐方案:CDC(实时增量)+ 定时全量(兜底校正)

三、索引设计

商品搜索索引
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"analysis": {
"analyzer": {
"ik_smart_pinyin": {
"type": "custom",
"tokenizer": "ik_smart",
"filter": ["pinyin_filter", "lowercase"]
}
},
"filter": {
"pinyin_filter": {
"type": "pinyin",
"keep_original": true,
"keep_first_letter": true
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"fields": {
"pinyin": { "type": "text", "analyzer": "ik_smart_pinyin" },
"keyword": { "type": "keyword" }
}
},
"description": { "type": "text", "analyzer": "ik_max_word" },
"category": { "type": "keyword" },
"price": { "type": "double" },
"sales": { "type": "integer" },
"created_at": { "type": "date" },
"suggest": { "type": "completion" }
}
}
}

四、搜索查询

综合搜索请求
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "苹果手机",
"fields": ["title^3", "title.pinyin", "description"],
"type": "best_fields"
}
}
],
"filter": [
{ "term": { "category": "手机" } },
{ "range": { "price": { "gte": 1000, "lte": 10000 } } }
]
}
},
"sort": [
{ "_score": "desc" },
{ "sales": "desc" }
],
"highlight": {
"fields": { "title": {}, "description": {} },
"pre_tags": ["<em>"],
"post_tags": ["</em>"]
},
"aggs": {
"categories": { "terms": { "field": "category", "size": 10 } },
"price_range": {
"range": {
"field": "price",
"ranges": [
{ "to": 1000 },
{ "from": 1000, "to": 5000 },
{ "from": 5000 }
]
}
}
},
"from": 0,
"size": 20
}

五、搜索建议(自动补全)

{
"suggest": {
"title-suggest": {
"prefix": "苹果",
"completion": {
"field": "suggest",
"size": 5,
"fuzzy": { "fuzziness": "AUTO" }
}
}
}
}

六、搜索优化

优化项说明
同义词扩展"手机" → "手机, 智能手机, 移动电话"
拼写纠错"pingguo" → "苹果"
拼音搜索"pingguo" 可以搜到 "苹果"
停用词过滤去掉"的"、"了"等无意义词
结果缓存热门搜索词的结果缓存到 Redis
深分页优化使用 search_after 替代 from + size

常见面试问题

Q1: ES 和 MySQL LIKE 查询的区别?

答案

维度MySQL LIKEElasticsearch
查询方式LIKE '%keyword%' 全表扫描倒排索引精确命中
性能百万级数据就慢亿级数据毫秒响应
分词不分词,精确匹配分词后匹配
相关性无评分TF-IDF / BM25 评分
高亮需应用层处理内置支持

Q2: 如何保证 ES 和 MySQL 的数据一致性?

答案

  1. CDC 增量同步:Canal 监听 binlog,准实时同步
  2. 定时全量校验:每天凌晨对比两边数据量和抽样内容
  3. 补偿机制:发现不一致自动重新同步
  4. 容忍短暂不一致:搜索场景允许秒级延迟,MySQL 是主数据源

相关链接