Elasticsearch 第2章:核心概念

忘机山人

发布于184天前
博客图片修整中,看不了可以先搜索公众号“忘机山人”看。
# 


https://appstore.lazycat.cloud/#/shop/detail/xu.deploy.elasticsearch


> 本章导读:本章将详细介绍 Elasticsearch 的核心概念,包括索引、文档、映射、分片、副本、集群和节点等,这些概念是理解和使用 Elasticsearch 的基础。

## 目录

- [前置知识](#前置知识)
- [索引(Index)](#索引index)
- [文档(Document)](#文档document)
- [映射(Mapping)](#映射mapping)
- [分片(Shard)](#分片shard)
- [副本(Replica)](#副本replica)
- [集群(Cluster)](#集群cluster)
- [节点(Node)](#节点node)
- [概念关系图](#概念关系图)
- [本章小结](#本章小结)
- [参考资料](#参考资料)


## 索引(Index)

### 什么是索引

索引是 Elasticsearch 中存储数据的逻辑命名空间,类似于关系型数据库中的"数据库"概念。一个索引包含一组具有相似特征的文档。

### 索引命名规则

索引名称必须遵循以下规则:

- 只能使用小写字母
- 不能包含 `\`、`/`、`*`、`?`、`"`、``、`|`、空格、逗号、`#`
- 7.0 之前可以包含冒号 `:`,但已废弃
- 不能以 `-`、`_`、`+` 开头
- 不能是 `.` 或 `..`
- 长度不能超过 255 字节

### 索引示例

```json
// 创建索引
PUT /products
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}

// 查看索引信息
GET /products

// 查看所有索引
GET /_cat/indices?v

// 删除索引
DELETE /products
```

### 索引设置

索引有两类设置:

**静态设置**(创建后不可修改):
- `number_of_shards`:主分片数量

**动态设置**(可随时修改):
- `number_of_replicas`:副本数量
- `refresh_interval`:刷新间隔
- `max_result_window`:最大返回结果数

```json
// 修改动态设置
PUT /products/_settings
{
  "index": {
    "number_of_replicas": 2,
    "refresh_interval": "30s"
  }
}
```

## 文档(Document)

### 什么是文档

文档是 Elasticsearch 中的基本数据单元,以 JSON 格式存储。每个文档都属于一个索引,并有一个唯一的 ID。

### 文档结构

一个文档包含以下元数据:

| 元数据 | 说明 |
|--------|------|
| `_index` | 文档所属的索引 |
| `_id` | 文档的唯一标识符 |
| `_source` | 文档的原始 JSON 内容 |
| `_version` | 文档版本号 |
| `_seq_no` | 序列号,用于并发控制 |
| `_primary_term` | 主分片任期号 |

### 文档操作示例

```json
// 创建文档(指定 ID)
PUT /products/_doc/1
{
  "name": "iPhone 15",
  "price": 7999,
  "category": "手机",
  "brand": "Apple",
  "created_at": "2024-01-01"
}

// 创建文档(自动生成 ID)
POST /products/_doc
{
  "name": "MacBook Pro",
  "price": 14999,
  "category": "笔记本",
  "brand": "Apple"
}

// 获取文档
GET /products/_doc/1

// 更新文档
POST /products/_update/1
{
  "doc": {
    "price": 7499
  }
}

// 删除文档
DELETE /products/_doc/1
```

### 文档 ID

- **自动生成**:使用 POST 方法时,ES 自动生成 20 字符的 Base64 编码 ID
- **手动指定**:使用 PUT 方法时,可以指定任意字符串作为 ID

```json
// 自动生成 ID
POST /products/_doc
{
  "name": "Product A"
}
// 返回: "_id": "abc123xyz..."

// 手动指定 ID
PUT /products/_doc/my-product-001
{
  "name": "Product B"
}
// 返回: "_id": "my-product-001"
```

## 映射(Mapping)

### 什么是映射

映射定义了文档及其字段如何存储和索引。类似于关系型数据库中的表结构定义(Schema)。

### 字段类型

Elasticsearch 支持多种字段类型:

**核心类型**:

| 类型 | 说明 | 示例 |
|------|------|------|
| `text` | 全文搜索文本 | 商品描述、文章内容 |
| `keyword` | 精确值 | 状态、标签、ID |
| `long` | 长整型 | 大数值 |
| `integer` | 整型 | 数量、年龄 |
| `double` | 双精度浮点 | 价格、评分 |
| `boolean` | 布尔值 | 是否上架 |
| `date` | 日期 | 创建时间 |
| `object` | JSON 对象 | 嵌套属性 |
| `nested` | 嵌套对象数组 | 评论列表 |

**特殊类型**:

| 类型 | 说明 |
|------|------|
| `geo_point` | 地理坐标点 |
| `geo_shape` | 地理形状 |
| `ip` | IP 地址 |
| `completion` | 自动补全 |
| `dense_vector` | 稠密向量 |

### 映射示例

```json
// 创建索引时定义映射
PUT /products
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "standard",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "price": {
        "type": "double"
      },
      "category": {
        "type": "keyword"
      },
      "description": {
        "type": "text"
      },
      "created_at": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      },
      "is_available": {
        "type": "boolean"
      },
      "tags": {
        "type": "keyword"
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}

// 查看映射
GET /products/_mapping
```

### 动态映射

当索引一个包含新字段的文档时,Elasticsearch 会自动推断字段类型:

| JSON 类型 | 推断的 ES 类型 |
|-----------|----------------|
| `true` / `false` | `boolean` |
| 整数 | `long` |
| 浮点数 | `double` |
| 日期格式字符串 | `date` |
| 其他字符串 | `text` + `keyword` |
| 对象 | `object` |
| 数组 | 取决于第一个元素 |

```json
// 控制动态映射行为
PUT /products
{
  "mappings": {
    "dynamic": "strict",  // true(默认)/false/strict
    "properties": {
      "name": { "type": "text" }
    }
  }
}
```

- `true`:自动添加新字段(默认)
- `false`:忽略新字段,不索引但保存在 `_source`
- `strict`:遇到新字段抛出异常

## 分片(Shard)

### 什么是分片

分片是索引的水平分割单元。每个分片本质上是一个独立的 Lucene 索引,可以独立执行索引和搜索操作。

### 为什么需要分片

1. **水平扩展**:数据量超过单节点容量时,分片允许数据分布到多个节点
2. **并行处理**:搜索可以在多个分片上并行执行,提高性能
3. **高可用**:配合副本机制,提供故障容错能力

### 分片类型

```
┌─────────────────────────────────────────────────────────┐
│                      索引 (Index)                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Primary 0   │  │ Primary 1   │  │ Primary 2   │     │
│  │ (主分片)    │  │ (主分片)    │  │ (主分片)    │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
│         │               │               │               │
│         ▼               ▼               ▼               │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Replica 0   │  │ Replica 1   │  │ Replica 2   │     │
│  │ (副本分片)  │  │ (副本分片)  │  │ (副本分片)  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

- **主分片(Primary Shard)**:处理索引写入请求,每个文档只属于一个主分片
- **副本分片(Replica Shard)**:主分片的复制,用于故障转移和读取负载均衡

### 分片配置

```json
// 创建索引时指定分片数
PUT /products
{
  "settings": {
    "number_of_shards": 3,      // 主分片数(创建后不可修改)
    "number_of_replicas": 1     // 每个主分片的副本数(可动态修改)
  }
}
```

### 分片数量规划

**经验法则**:
- 单个分片大小建议在 10GB - 50GB 之间
- 分片数 = 预计数据量 / 单分片大小
- 考虑未来增长,但不要过度分片

**过度分片的问题**:
- 每个分片消耗资源(内存、文件句柄)
- 搜索需要协调更多分片,增加开销
- 集群状态膨胀

```json
// 查看分片分布
GET /_cat/shards/products?v
```

## 副本(Replica)

### 什么是副本

副本是主分片的完整复制。每个主分片可以有零个或多个副本。

### 副本的作用

1. **高可用**:主分片所在节点故障时,副本可以提升为主分片
2. **读取扩展**:搜索请求可以在主分片或副本上执行,提高读取吞吐量
3. **数据冗余**:防止数据丢失

### 副本配置

```json
// 修改副本数量
PUT /products/_settings
{
  "index": {
    "number_of_replicas": 2
  }
}
```

### 副本分配规则

- 副本不会与其主分片分配在同一节点上
- 如果节点数少于副本数 + 1,部分副本将无法分配

```
节点数 = 1,副本数 = 1
┌─────────────────┐
│     Node 1      │
│  ┌───────────┐  │
│  │ Primary 0 │  │
│  └───────────┘  │
│  ┌───────────┐  │
│  │ Replica 0 │  │  ← 无法分配!
│  │ UNASSIGNED│  │
│  └───────────┘  │
└─────────────────┘

节点数 = 2,副本数 = 1
┌─────────────────┐  ┌─────────────────┐
│     Node 1      │  │     Node 2      │
│  ┌───────────┐  │  │  ┌───────────┐  │
│  │ Primary 0 │  │  │  │ Replica 0 │  │  ← 正常分配
│  └───────────┘  │  │  └───────────┘  │
└─────────────────┘  └─────────────────┘
```

## 集群(Cluster)

### 什么是集群

集群是一组协同工作的 Elasticsearch 节点。集群通过唯一的名称标识,默认名称为 `elasticsearch`。

### 集群健康状态

集群有三种健康状态:

| 状态 | 颜色 | 说明 |
|------|------|------|
| Green | 🟢 | 所有主分片和副本分片都已分配 |
| Yellow | 🟡 | 所有主分片已分配,但部分副本未分配 |
| Red | 🔴 | 部分主分片未分配,数据不完整 |

```json
// 查看集群健康状态
GET /_cluster/health

// 返回示例
{
  "cluster_name": "my-cluster",
  "status": "green",
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 10,
  "active_shards": 20,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0
}
```

### 集群配置

```yaml
# elasticsearch.yml
cluster.name: my-cluster
node.name: node-1
network.host: 0.0.0.0
discovery.seed_hosts: ["node1:9300", "node2:9300", "node3:9300"]
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
```

## 节点(Node)

### 什么是节点

节点是集群中的单个 Elasticsearch 实例。每个节点都有唯一的名称和角色。

### 节点角色

| 角色 | 配置 | 说明 |
|------|------|------|
| Master | `node.roles: [master]` | 管理集群状态、索引创建删除、分片分配 |
| Data | `node.roles: [data]` | 存储数据、执行 CRUD、搜索、聚合 |
| Ingest | `node.roles: [ingest]` | 执行 Ingest Pipeline 预处理 |
| Coordinating | `node.roles: []` | 路由请求、合并结果(无特定角色) |
| ML | `node.roles: [ml]` | 执行机器学习任务 |
| Remote Cluster Client | `node.roles: [remote_cluster_client]` | 跨集群搜索 |

### 节点角色组合

```yaml
# 专用主节点
node.roles: [master]

# 专用数据节点
node.roles: [data]

# 数据 + Ingest 节点
node.roles: [data, ingest]

# 协调节点(无角色)
node.roles: []

# 默认(所有角色)
node.roles: [master, data, data_content, data_hot, data_warm, data_cold, ingest, ml, remote_cluster_client, transform]
```

### 节点信息查看

```json
// 查看所有节点
GET /_cat/nodes?v

// 查看节点详细信息
GET /_nodes

// 查看特定节点统计
GET /_nodes/stats
```

## 概念关系图

```
┌─────────────────────────────────────────────────────────────────────┐
│                           Cluster (集群)                             │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                        Node 1 (节点)                         │   │
│  │  ┌─────────────────────────────────────────────────────┐    │   │
│  │  │                   Index (索引)                       │    │   │
│  │  │  ┌─────────────┐  ┌─────────────┐                   │    │   │
│  │  │  │  Shard P0   │  │  Shard R1   │                   │    │   │
│  │  │  │ ┌─────────┐ │  │             │                   │    │   │
│  │  │  │ │Document │ │  │             │                   │    │   │
│  │  │  │ │ _id: 1  │ │  │             │                   │    │   │
│  │  │  │ │ _source │ │  │             │                   │    │   │
│  │  │  │ └─────────┘ │  │             │                   │    │   │
│  │  │  │ ┌─────────┐ │  │             │                   │    │   │
│  │  │  │ │Document │ │  │             │                   │    │   │
│  │  │  │ │ _id: 2  │ │  │             │                   │    │   │
│  │  │  │ └─────────┘ │  │             │                   │    │   │
│  │  │  └─────────────┘  └─────────────┘                   │    │   │
│  │  │                                                     │    │   │
│  │  │  Mapping (映射): 定义字段类型和索引方式              │    │   │
│  │  └─────────────────────────────────────────────────────┘    │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                        Node 2 (节点)                         │   │
│  │  ┌─────────────┐  ┌─────────────┐                           │   │
│  │  │  Shard P1   │  │  Shard R0   │                           │   │
│  │  └─────────────┘  └─────────────┘                           │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
```

### 概念对比:ES vs 关系型数据库

| Elasticsearch | 关系型数据库 | 说明 |
|---------------|--------------|------|
| Index | Database | 数据的逻辑容器 |
| Mapping | Schema | 数据结构定义 |
| Document | Row | 数据的基本单元 |
| Field | Column | 数据的属性 |
| Shard | Partition | 数据的物理分割 |

> ⚠️ **注意**:这个对比仅用于帮助理解,ES 和关系型数据库的设计理念有本质区别。

## 本章小结

本章介绍了 Elasticsearch 的核心概念:

1. **索引(Index)**:存储数据的逻辑命名空间,包含设置和映射
2. **文档(Document)**:基本数据单元,JSON 格式,有唯一 ID
3. **映射(Mapping)**:定义字段类型和索引方式,支持动态和显式映射
4. **分片(Shard)**:索引的水平分割,实现分布式存储和并行处理
5. **副本(Replica)**:主分片的复制,提供高可用和读取扩展
6. **集群(Cluster)**:多节点协同工作,有 Green/Yellow/Red 三种状态
7. **节点(Node)**:集群中的单个实例,可配置不同角色

理解这些概念是使用 Elasticsearch 的基础,后续章节将在此基础上深入讲解各个功能。

![image.png](https://dl.playground.lazycat.cloud/guidelines/459/7d2ed776-4462-45b9-a797-a32f1b3b7724.png "image.png")

## 参考资料

- [Elasticsearch 索引概念](https://www.elastic.co/guide/en/elasticsearch/reference/current/documents-indices.html)
- [映射类型](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html)
- [分片分配](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-allocation.html)
- [集群健康](https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html)

评论

0

暂无评论

说点什么呢~
收藏
0
0
0