为什么不用数据库 like 查
站内搜索、商品搜索、日志检索这些场景,用 MySQL 的 like '%关键词%' 会两个问题:走不了索引、全表扫描慢,而且只能整词匹配、无法分词、无法相关度排序。Elasticsearch 正是为全文检索而生的:它把文本切成词、建成倒排索引,支持毫秒级返回"按相关度排序"的结果,还能做聚合分析。
选型上:精确查找用数据库,模糊全文检索用 Elasticsearch。订单号、用户 ID 这类等值查询留在 MySQL;商品描述、文章内容、日志内容这类"包含某词并排序"的检索交给 ES。
- 倒排索引词到文档的映射,是全文检索的根基。
- 分词器中文搜索的成败很大程度取决于分词。
- 查询 DSLbool 组合 must/should/filter 控制召回与评分。
- 集群分片、副本、写入与查询性能调优。
倒排索引与分词
传统索引是"文档→词",倒排索引反过来是"词→哪些文档包含它"。建索引时先把文本分词:"后端开发实战"被切成"后端""开发""实战"等词,每个词记录它出现在哪些文档、出现几次、位置在哪。搜索时拿关键词直接查倒排表,毫秒定位,还能按词频、位置算出相关度评分。
中文搜索的关键在分词器:默认分词按单字切,效果差;要装中文分词插件(如 IK 分词器),把句子切成有意义的词。分词选错,搜"后端"可能召回一堆单字结果,这是新手最常踩的坑。
索引建模与 mapping
建索引时先定义 mapping,告诉 ES 每个字段是什么类型、用什么分词器。text 类型会被分词建倒排索引,适合搜索;keyword 类型不分词,适合精确过滤、排序、聚合。同一个字段常同时建 text 和 keyword(用 fields),搜索走 text、按品牌精确过滤走 keyword。
PUT /goods
{
"mappings": {
"properties": {
"title": { "type": "text", "analyzer": "ik_max_word" },
"brand": { "type": "keyword" },
"price": { "type": "scaled_float" }
}
}
}
查询 DSL:bool 与评分
ES 的查询用 JSON 描述,核心是 bool 查询:must 必须命中并参与相关度评分,filter 必须命中但不评分(常用于价格区间、品牌过滤,还能缓存),should 可选命中、命中了加分。混在一起就能表达"标题包含手机、价格在 1000-3000、品牌是华为或小米"这类复杂条件。
GET /goods/_search
{
"query": {
"bool": {
"must": [{ "match": { "title": "手机" } }],
"filter": [{ "range": { "price": { "gte": 1000, "lte": 3000 } } }],
"should": [{ "term": { "brand": "华为" } }]
}
}
}
聚合与数据分析
ES 不只是搜索,还能做实时聚合分析:按品牌分组统计销量、按价格区间分桶、统计平均值。aggregations 让你在一次查询里既拿到搜索结果、又拿到分面统计("这个词搜出来共多少条、各品牌分布如何"),这正是电商搜索页左侧筛选栏的数据来源。
写入、分片与性能优化
ES 把索引拆成分片分布到多台节点,分片数建索引时定好、之后不能随意改。写入优化:批量写、加大刷新间隔、用合适的副本数;查询优化:用 filter 代替 must 以利用缓存、避免深度分页(from + size 太深会拖慢,用 search_after)。内存给足堆、但别太大,剩下的留给文件系统缓存——ES 大量依赖操作系统缓存。
与 MySQL 的配合
实际工程里 ES 通常不是唯一数据源,而是 MySQL 的"检索副本"。数据先写 MySQL,再通过同步机制(binlog 订阅、消息队列)把变更同步到 ES。查询时:列表展示、详情从 MySQL 取,模糊搜索、分面聚合从 ES 取。这样既保留事务与强一致,又有全文检索能力。
实战清单
落地清单:
- 精确查找留数据库,模糊检索交给 ES。
- 中文务必用好分词器(IK),别用默认单字。
- text 用于搜索、keyword 用于过滤排序。
- bool 查询里用 filter 做不评分的过滤条件。
- 深度分页用 search_after,别用大 from。
- ES 作为检索副本,通过 binlog/消息同步 MySQL。
Elasticsearch 的价值在于把"全文检索 + 实时聚合"从数据库手里接过来,让搜索既快又能按相关度排序。把分词、mapping、查询 DSL 这三件事用对,站内搜索体验会有质的提升。