为什么不用数据库 like 查

站内搜索、商品搜索、日志检索这些场景,用 MySQL 的 like '%关键词%' 会两个问题:走不了索引、全表扫描慢,而且只能整词匹配、无法分词、无法相关度排序。Elasticsearch 正是为全文检索而生的:它把文本切成词、建成倒排索引,支持毫秒级返回"按相关度排序"的结果,还能做聚合分析。

选型上:精确查找用数据库,模糊全文检索用 Elasticsearch。订单号、用户 ID 这类等值查询留在 MySQL;商品描述、文章内容、日志内容这类"包含某词并排序"的检索交给 ES。

本文核心知识点
  • 倒排索引词到文档的映射,是全文检索的根基。
  • 分词器中文搜索的成败很大程度取决于分词。
  • 查询 DSLbool 组合 must/should/filter 控制召回与评分。
  • 集群分片、副本、写入与查询性能调优。
Elasticsearch 搜索引擎配图:蓝色渐变背景上一个发光放大镜,镜片下堆叠索引方块与文档卡片,右侧漏斗形数据流入索引体
放大镜代表检索,漏斗代表从原始文档到倒排索引的建立过程。

倒排索引与分词

传统索引是"文档→词",倒排索引反过来是"词→哪些文档包含它"。建索引时先把文本分词:"后端开发实战"被切成"后端""开发""实战"等词,每个词记录它出现在哪些文档、出现几次、位置在哪。搜索时拿关键词直接查倒排表,毫秒定位,还能按词频、位置算出相关度评分。

中文搜索的关键在分词器:默认分词按单字切,效果差;要装中文分词插件(如 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 大量依赖操作系统缓存。