Elasticsearch(简称 ES)是一款基于 Lucene 构建的分布式、高扩展、高实时的全文搜索引擎,同时也是 Elastic Stack(ELK Stack:Elasticsearch, Logstash, Kibana)的核心组件,广泛应用于日志分析、全文检索、实时数据分析等场景。本文将从核心概念、架构设计、数据操作、查询分析、性能优化等维度进行全面总结。

一、核心概念

Elasticsearch 的概念体系与传统数据库有显著差异,理解这些基础概念是掌握 ES 的前提。

1. 与传统数据库的对应关系

为便于快速理解,可将 ES 核心概念与关系型数据库(如 MySQL)进行类比:

Elasticsearch 概念关系型数据库概念说明
Index(索引)Database(数据库)存储同类文档的集合,具有相似的结构
Type(类型,7.x 后废弃)Table(表)早期用于对 Index 内文档分类,7.x 起强制为 _doc
Document(文档)Row(行)索引中最小的数据单元,以 JSON 格式存储
Field(字段)Column(列)文档中的属性,对应 JSON 的键值对
Mapping(映射)Schema(表结构)定义文档中字段的类型、分词器、是否索引等元数据
Shard(分片)-索引的物理分片,实现水平扩展(Lucene 索引实例)
Replica(副本)-分片的冗余备份,用于高可用和负载分担

2. 核心概念详解

(1)Index(索引)
  • 定义:一个逻辑上的集合,包含具有相似结构的文档(如“商品索引”“用户日志索引”)。
  • 命名规则: lowercase 小写,无特殊字符(建议用 - 分隔,如 user-logs-2024)。
  • 特点:索引是分片的逻辑容器,创建时需指定分片和副本数量,创建后分片数量不可修改(副本可动态调整)。
(2)Document(文档)
  • 格式:唯一支持 JSON 格式,灵活性高(无需严格统一结构,但建议遵循 Mapping 规范)。
  • 唯一标识:由 _index(所属索引)、_type(7.x 固定为 _doc)、_id(文档 ID)共同确定。
    • _id 可手动指定(如用业务 ID 作为 _id),也可由 ES 自动生成(20 位 UUID)。
  • 元数据:除业务字段外,包含 _index_type_id_version(版本号)、_score(查询相关性得分)等系统字段。
(3)Mapping(映射)
  • 定义:相当于文档的“ schema ”,用于约束字段的类型、分词方式、是否可检索等属性。
  • 类型
    • 动态映射(Dynamic Mapping):ES 自动根据文档字段值推断类型(如数字→long,字符串→text/keyword),适合快速上手,但可能存在精度问题。
    • 静态映射(Explicit Mapping):手动定义字段类型和属性,适合生产环境,保证数据结构一致性。
  • 常见字段类型
    • 文本类:text(可分词,用于全文检索,如“商品描述”)、keyword(不分词,用于精确匹配/聚合,如“商品分类”)。
    • 数值类:longintegerdoublefloat(对应不同精度的数字)。
    • 日期类:date(支持格式化,如 yyyy-MM-dd HH:mm:ss)。
    • 布尔类:booleantrue/false)。
    • 复合类:object(嵌套对象)、nested(处理嵌套数组,解决 object 类型的扁平化问题)。
(4)Shard & Replica(分片与副本)
  • Shard(分片)

    • 核心目的:实现水平扩展。单个索引的数据被拆分到多个分片,每个分片是独立的 Lucene 索引,可分布在不同节点。
    • 类型:主分片(Primary Shard)、副本分片(Replica Shard)。
    • 数量限制:创建索引时指定主分片数量(number_of_shards),创建后不可修改(需通过 reindex 重建索引调整);默认 1 个主分片。
  • Replica(副本)

    • 核心目的:高可用 + 负载分担。副本是主分片的冗余备份,主分片故障时可自动升级为主分片;同时可承担查询请求,缓解主分片压力。
    • 数量配置:创建时通过 number_of_replicas 指定,支持动态修改(如 PUT /index/_settings {"number_of_replicas": 2});默认 1 个副本。
    • 约束:副本分片不会与对应的主分片在同一节点(避免单点故障)。
(5)Cluster & Node(集群与节点)
  • Node(节点)

    • 定义:运行 ES 进程的单个服务器,是集群的基本组成单元。
    • 类型:
      • 主节点(Master Node):负责集群元数据管理(如创建索引、分片分配),默认所有节点均可竞选,建议通过 node.master: true 专门配置。
      • 数据节点(Data Node):负责数据的存储、索引、查询和聚合,通过 node.data: true 配置,是集群的“数据载体”。
      • 协调节点(Coordinating Node):接收客户端请求,分发到其他节点,汇总结果返回;默认所有节点都是协调节点,可通过 node.master: false + node.data: false 配置专用协调节点。
      • ingest 节点:负责数据预处理(如添加字段、转换格式),通过 node.ingest: true 配置。
  • Cluster(集群)

    • 定义:由多个节点组成的集合,共享同一集群名称(cluster.name),协同工作实现分布式能力。
    • 集群状态:通过 _cluster/health 查看,状态分为 green(所有主/副本分片正常)、yellow(主分片正常,副本分片缺失)、red(主分片缺失,数据不可用)。

二、架构设计

Elasticsearch 的分布式架构是其高扩展、高可用的核心,主要围绕“分片分配”“路由机制”“故障转移”展开。

1. 分片路由机制

当客户端写入/查询文档时,ES 需要确定文档归属的主分片,核心逻辑如下:

  1. 计算路由值:shard = hash(_routing) % number_of_primary_shards
  2. _routing 默认为文档的 _id,可手动指定(如按“用户 ID”路由,确保同一用户的文档在同一分片,优化聚合效率)。
  3. 协调节点根据路由结果,将请求转发到主分片所在节点;写入操作需等待主分片和副本分片均确认后返回成功(默认配置)。

2. 分片分配与再平衡

  • 分配策略:Master 节点负责将主分片和副本分片分配到不同节点,遵循“副本不与主分片同节点”“分片均匀分布”等原则。
  • 再平衡(Rebalancing):当集群节点数量变化(新增/下线节点)或分片状态变化时,Master 会自动触发分片迁移,确保负载均衡;可通过 cluster.routing.rebalance.enable 控制开关。

3. 故障转移机制

当主节点故障或主分片不可用时,ES 自动执行故障转移:

  1. 节点间通过 ZenDiscovery 协议选举新的主节点(需满足“法定人数”,避免脑裂,可配置 discovery.zen.minimum_master_nodes)。
  2. 新主节点将该主分片对应的副本分片升级为新的主分片。
  3. 重新创建缺失的副本分片,恢复集群状态为 green

三、数据操作(CRUD)

ES 提供 RESTful API 用于数据交互,核心操作包括索引(Index)、查询(Search)、更新(Update)、删除(Delete)。

1. 文档操作

(1)创建文档(Index)
  • 手动指定 _id
1
2
3
4
5
PUT /<index>/_doc/<_id>
{
"field1": "value1",
"field2": "value2"
}
  • 自动生成 _id(用 POST):
1
2
3
4
POST /<index>/_doc/
{
"field1": "value1"
}
(2)查询文档(Get)
  • _id 精确查询:
1
GET /<index>/_doc/<_id>
  • 查询文档是否存在:
1
HEAD /<index>/_doc/<_id>  # 200 存在,404 不存在
(3)更新文档(Update)
  • 全量更新(覆盖原有文档,_version 自增):直接用 PUT 重写文档。
  • 局部更新(仅修改指定字段):
1
2
3
4
5
6
POST /<index>/_doc/<_id>/_update
{
"doc": {
"field1": "new_value"
}
}
(4)删除文档(Delete)
1
DELETE /<index>/_doc/<_id>

2. 索引操作

(1)创建索引(含 Mapping)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
PUT /<index>
{
"settings": {
"number_of_shards": 3, # 主分片数量
"number_of_replicas": 1 # 副本数量
},
"mappings": {
"properties": {
"title": {
"type": "text", # 可分词,用于全文检索
"analyzer": "ik_max_word" # 中文分词器
},
"category": {
"type": "keyword" # 不分词,用于精确匹配
},
"price": {
"type": "double"
},
"create_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
(2)删除索引
1
2
3
DELETE /<index>  # 删除单个索引
DELETE /<index1>,<index2> # 删除多个索引
DELETE /* # 删除所有索引(谨慎使用!)
(3)查看索引信息
  • 查看索引设置:GET /<index>/_settings
  • 查看索引 Mapping:GET /<index>/_mapping
  • 查看索引统计信息:GET /<index>/_stats

四、查询与分析

查询是 ES 的核心能力,支持全文检索、精确匹配、聚合分析等复杂场景,查询语法通过 Query DSL(Domain Specific Language)定义。

1. 查询类型分类

ES 的查询分为两大类:

类型特点代表查询
叶子查询(Leaf Queries)直接查询字段值,可单独使用匹配查询(match)、精确匹配(term)、范围查询(range)
复合查询(Compound Queries)组合多个叶子查询或其他复合查询布尔查询(bool)、嵌套查询(nested)、函数评分查询(function_score)

2. 常用核心查询

(1)匹配查询(match)
  • 用于 text 类型字段的全文检索,会对查询词分词后匹配。
  • 示例:查询“手机”相关的商品(“智能手机”“手机壳”均会匹配):
1
2
3
4
5
6
7
8
GET /products/_search
{
"query": {
"match": {
"title": "手机"
}
}
}
(2)精确匹配(term)
  • 用于 keyword 或数值类型字段的精确匹配,不对查询词分词。
  • 示例:查询分类为“手机”的商品(仅“手机”分类匹配,“智能手机”不匹配):
1
2
3
4
5
6
7
8
GET /products/_search
{
"query": {
"term": {
"category": "手机"
}
}
}
(3)范围查询(range)
  • 用于数值、日期类型字段的范围筛选,支持 gt(>)、gte(≥)、lt(<)、lte(≤)。
  • 示例:查询价格 1000-3000 元的商品:
1
2
3
4
5
6
7
8
9
10
11
GET /products/_search
{
"query": {
"range": {
"price": {
"gte": 1000,
"lte": 3000
}
}
}
}
(4)布尔查询(bool)
  • 组合多个子查询,通过 must(必须匹配)、should(可选匹配,加分)、must_not(必须不匹配)、filter(过滤,不影响评分)控制逻辑。
  • 示例:查询分类为“手机”、价格 1000-3000 元、标题含“华为”的商品:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /products/_search
{
"query": {
"bool": {
"must": [
{"term": {"category": "手机"}},
{"match": {"title": "华为"}}
],
"filter": [
{"range": {"price": {"gte": 1000, "lte": 3000}}}
]
}
}
}

3. 聚合分析(Aggregation)

聚合用于对查询结果进行统计分析(如分组、求和、排序),类似 SQL 的 GROUP BY + 聚合函数,分为桶聚合(Bucket)指标聚合(Metric)

(1)桶聚合(Bucket)
  • 按条件对数据分组,每个组称为一个“桶”,如按分类分组、按价格区间分组。
  • 示例:按“category”字段分组,统计每个分类的商品数量:
1
2
3
4
5
6
7
8
9
10
11
12
GET /products/_search
{
"size": 0, # 不返回原始文档,仅返回聚合结果
"aggs": {
"category_count": { # 聚合名称(自定义)
"terms": { # 桶聚合类型:按字段值分组
"field": "category",
"size": 10 # 返回前 10 个分组
}
}
}
}
(2)指标聚合(Metric)
  • 对桶内数据进行数值计算,如求和、平均值、最大值等。
  • 示例:按分类分组,统计每个分类的商品平均价格:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /products/_search
{
"size": 0,
"aggs": {
"category_avg_price": {
"terms": {"field": "category"},
"aggs": { # 嵌套指标聚合
"avg_price": {
"avg": {"field": "price"} # 指标聚合类型:求平均值
}
}
}
}
}

五、分词器(Analyzer)

分词是全文检索的核心步骤,将文本拆分为可索引的“词条(Term)”,ES 的分词能力依赖于分词器。

1. 分词器组成

一个完整的分词器由 3 部分组成:

  1. Character Filter(字符过滤器):预处理文本(如去除 HTML 标签、替换特殊字符),可选。
  2. Tokenizer(分词器):将文本拆分为词条(如按空格、标点拆分),必须。
  3. Token Filter(词条过滤器):处理词条(如小写转换、停用词移除、同义词替换),可选。

2. 内置分词器

  • Standard Analyzer:默认分词器,按 Unicode 文本分割,小写转换,移除标点。
  • Simple Analyzer:按非字母字符分割,小写转换。
  • Whitespace Analyzer:仅按空格分割,不做其他处理。
  • Keyword Analyzer:不分词,将整个文本作为一个词条。

3. 中文分词器

内置分词器对中文支持差(如将“我爱中国”拆分为“我”“爱”“中”“国”),需引入第三方分词器:

  • IK Analyzer:最常用的中文分词器,支持自定义词典,有两种模式:
    • ik_max_word:最大粒度分词(如“中华人民共和国”→“中华人民共和国”“中华人民”“中华”“中国”等)。
    • ik_smart