Skip to content

Elasticsearch 是什么?

大家好,这篇我们来聊 Elasticsearch,后面简称 ES。

很多同学第一次接触 ES,容易把它当成一个“更快的数据库”。这个理解只对了一半。ES 确实能存 JSON 文档,也能通过 HTTP API 查询数据,但它真正擅长的是搜索和分析,尤其是全文检索、组合过滤、聚合统计和相关性排序。

ES 适合解决什么问题?

我们先看几个典型场景:

  • 电商里搜索“苹果手机 256G”,要能搜到标题、品牌、类目、标签里相关的商品。
  • 日志平台里按服务名、错误码、时间范围过滤,再对错误数量做聚合统计。
  • 内容系统里按关键词召回文章,并根据时间、标签权重、点击量重新排序。
  • 地图或门店系统里按城市、距离、营业状态筛选结果。

这些需求的共同点是:查询条件多,字段类型多,经常既要“过滤”,又要“排序”,还要算“相关度”。这就是 ES 发光的地方。

但 ES 不适合作为强事务数据库使用。它不提供 MySQL 那样的多行事务能力,也不适合频繁地对同一批数据做复杂关联更新。如果数据源来自业务库,常见做法是 MySQL 负责交易事实,ES 负责搜索视图。

ES 的核心概念

ES 里有几个概念经常一起出现:

  • Index:索引,可以类比 MySQL 的一张表,但更准确地说,它是一批相同业务文档的逻辑集合。
  • Document:文档,一条 JSON 数据,是 ES 存储和检索的基本单位。
  • Field:字段,文档里的属性,比如 title、price、publishTime。
  • Mapping:字段定义,描述字段类型、是否分词、使用什么分词器等。
  • Shard:分片,一个索引会被拆成多个分片,分散存到不同节点上。
  • Replica:副本分片,用于高可用和分担读请求。
  • Node:节点,一个 ES 进程。
  • Cluster:集群,由多个节点组成。

举个例子,一个 articles 索引可能有 3 个主分片,每个主分片有 1 个副本。写入一篇文章时,ES 会根据 _id_routing 计算它属于哪个主分片,然后写入该主分片,再复制到副本分片。

为什么 ES 搜文本快?

MySQL 常见索引结构是 B+ 树。它适合按照字段值从左到右定位,比如 id = 10age between 18 and 30name like 'abc%'

但是全文检索的问题不一样。假设有三篇文章:

text
doc1: 我喜欢学习 Elasticsearch
doc2: Elasticsearch 适合做全文搜索
doc3: MySQL 适合做事务存储

如果用户搜索 Elasticsearch 搜索,我们希望快速知道哪些文档包含这些词。倒排索引的思路是反过来建索引:

text
Elasticsearch -> doc1, doc2
搜索            -> doc2
MySQL           -> doc3

这样查询某个词时,不需要逐篇扫描文章,只要先找到词典里的 term,再拿到包含这个 term 的文档列表。这个“term 到 document”的映射,就是倒排索引的核心。

分词决定能不能搜到

倒排索引里记录的是分词后的 term,不一定是原始句子。

比如字段 title 的值是:

text
中华人民共和国国歌

如果使用标准分词器处理中文,效果可能比较粗糙;如果使用 IK 分词器,可能得到:

text
中华人民共和国、中华人民、中华、人民、共和国、国歌

因此,搜索能不能命中,和字段使用什么 analyzer 有直接关系。写入时怎么分词,查询时怎么分词,两边要能对得上。

text 和 keyword 的区别

ES 里字符串字段最常见的是两种类型:

  • text:会分词,适合全文检索,比如标题、正文、简介。
  • keyword:不分词,适合精确匹配、排序、聚合,比如状态、标签、用户 ID、订单号。

比如 author = "金十期货"

  • 如果是 text 字段,可能会被分成多个词,适合 match 查询。
  • 如果是 keyword 字段,会作为一个整体保存,适合 term 查询。

很多业务字段会使用多字段设计:

json
PUT /articles
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": { "type": "keyword" }
        }
      }
    }
  }
}

这样 title 可以做全文检索,title.keyword 可以做精确匹配、排序或聚合。

ES 为什么是分布式的?

单机 Lucene 已经能完成倒排索引和搜索,但单机容量、性能和可用性都有限。ES 在 Lucene 之上加了一层分布式能力:

  • 一个索引可以拆成多个主分片,分布到多个节点。
  • 每个主分片可以有副本分片,节点宕机后副本可以提升为主分片。
  • 查询可以发到任意节点,由协调节点把请求转发到相关分片,再合并结果。
  • 集群会维护索引元数据、分片分配、节点状态等信息。

在 ES 集群里,请求进入的节点叫协调节点。协调节点不一定保存目标数据,但它会负责路由请求、收集分片结果、排序分页,最后把结果返回给客户端。

集群健康状态怎么看?

ES 常见的集群健康状态有三种:

  • green:主分片和副本分片都正常分配。
  • yellow:主分片正常,但至少有副本分片没有分配。
  • red:至少有主分片没有分配,部分数据不可用。

查看健康状态:

http
GET /_cluster/health

查看节点和分片:

http
GET /_cat/nodes?v
GET /_cat/shards?v
GET /_cat/indices?v

yellow 不一定代表数据不可读,比如单节点集群设置了 1 个副本,副本无法分配到另一个节点,就会是 yellow。但 red 要认真处理,因为它说明有主分片不可用。

ES 和 MySQL 怎么分工?

常见架构是:

text
业务写入 -> MySQL -> binlog / MQ / 同步任务 -> Elasticsearch -> 搜索接口

MySQL 保存权威数据,负责事务、约束、精确更新;ES 保存搜索视图,负责快速检索和聚合。

这样做有一个重要前提:ES 里的数据通常是“最终一致”的。也就是说,业务库更新后,ES 可能稍晚一点才同步完成。对于搜索场景,这种延迟通常可以接受;对于支付、库存、账户余额这类强一致场景,就不应该依赖 ES 作为判断依据。

小结

ES 的核心可以用一句话概括:它把 JSON 文档按 Mapping 和 Analyzer 处理成 Lucene 索引,再通过分片和副本提供分布式搜索能力。

学习 ES 不要一开始就陷在 API 细节里,先把这条主线抓住:

  • Mapping 决定字段怎么存。
  • Analyzer 决定文本怎么分词。
  • 倒排索引决定搜索为什么快。
  • Shard 和 Replica 决定 ES 怎么扩展和高可用。
  • Query DSL 决定业务查询怎么表达。

后面我们再继续拆 ES 的写入、读取、Mapping 和查询细节。