Elasticsearch(ES)中的索引(Index) 是存储和管理数据的核心逻辑单元,类比关系型数据库的 “数据库(Database)”,是一组具有相似结构的文档(Document)的集合。以下从核心概念、索引生命周期、核心操作、设计原则、性能优化等维度全面解析,覆盖从基础到进阶的核心知识点:
一、索引的核心基础概念
1. 索引的三层类比(快速理解)
| Elasticsearch | 关系型数据库 | 说明 |
|---|---|---|
| 索引(Index) | 数据库(DB) | 逻辑上的数据集容器 |
| 类型(Type) | 表(Table) | ES 7.x+ 已废弃(仅保留 _doc),6.x 及更早版本用于区分索引内的文档类型 |
| 文档(Document) | 行(Row) | 索引的最小数据单元,JSON 格式 |
| 字段(Field) | 列(Column) | 文档的属性,对应映射(Mapping)中的定义 |
| 映射(Mapping) | 表结构(Schema) | 定义文档字段的类型、分词器、索引规则等 |
2. 索引的物理存储:分片(Shard)与副本(Replica)
ES 是分布式搜索引擎,索引会被拆分为多个分片(Shard) 分布在集群节点上,核心目的是横向扩展和负载均衡:
- 主分片(Primary Shard) :数据的原始存储分片,一个索引的主分片数在创建时指定,后续无法修改(需重建索引);
- 副本分片(Replica Shard) :主分片的冗余备份,用于故障容错和读请求负载均衡,副本数可动态调整;
- 示例:创建索引时指定
number_of_shards: 5(主分片)、number_of_replicas: 1(副本),则集群中该索引总分片数 = 5*(1+1) = 10。
3. 索引的元数据
每个索引会存储核心元数据:
- 索引名称(需符合命名规范:小写、无特殊字符、不以
-/_开头); - 分片配置(主分片 / 副本数);
- 映射(Mapping):字段类型、分词规则、是否索引等;
- 设置(Settings):如分片数、刷新间隔、分析器、缓存策略等。
二、索引的核心操作(CRUD)
1. 创建索引(Create)
核心语法:指定名称、分片配置、映射(可选)。
基础创建(默认配置)
PUT /my_index // 索引名:my_index
{
"settings": {
"number_of_shards": 3, // 主分片数(默认1,建议根据集群节点数设置)
"number_of_replicas": 1 // 副本数(默认1)
},
"mappings": { // 映射定义(可选,ES会自动推断字段类型,但建议显式定义)
"properties": {
"title": {
"type": "text", // 文本类型(支持分词,用于全文检索)
"analyzer": "ik_max_word", // 指定分词器(如IK中文分词)
"fields": {
"keyword": { // 多字段:同时支持分词检索和精准匹配
"type": "keyword",
"ignore_above": 256
}
}
},
"price": {"type": "integer"}, // 整型
"create_time": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"} // 日期类型
}
}
}
动态创建
写入文档时,若索引不存在,ES 会自动创建索引并根据文档字段类型推断映射(不推荐,易出现类型错误):
PUT /my_index/_doc/1 // 自动创建my_index,推断title为text、price为long
{
"title": "ES索引教程",
"price": 99
}
2. 查看索引(Read)
查看单个索引信息(配置 + 映射)
GET /my_index // 查看my_index的settings和mappings
GET /my_index/_settings // 仅查看设置
GET /my_index/_mapping // 仅查看映射
查看所有索引
GET /_cat/indices?v // 简洁格式(v:显示表头)
GET /_all // 查看所有索引的详细信息(不推荐,集群大时性能差)
3. 修改索引(Update)
索引的主分片数无法修改,仅能修改副本数、刷新间隔、分析器等动态配置:
// 修改副本数为2
PUT /my_index/_settings
{
"number_of_replicas": 2
}
// 修改刷新间隔(默认1s,批量写入时可调大提升性能)
PUT /my_index/_settings
{
"index.refresh_interval": "5s"
}
修改映射(仅新增字段 / 调整部分参数)
已存在的字段类型无法直接修改(会导致索引数据不一致),仅能新增字段或调整 ignore_above、null_value 等非核心参数:
// 给my_index新增字段tags
PUT /my_index/_mapping
{
"properties": {
"tags": {"type": "keyword"}
}
}
重建索引(修改已有字段类型的唯一方式)
若需修改已有字段类型(如 text 改 keyword),需创建新索引,通过 _reindex 迁移数据:
// 1. 创建新索引my_index_new,定义正确的映射
PUT /my_index_new
{
"mappings": {
"properties": {
"title": {"type": "keyword"}, // 原text改为keyword
"price": {"type": "integer"}
}
}
}
// 2. 迁移数据
POST /_reindex
{
"source": {"index": "my_index"},
"dest": {"index": "my_index_new"}
}
// 3. (可选)别名切换,业务无感知
PUT /_alias
{
"actions": [
{"remove": {"index": "my_index", "alias": "my_index_alias"}},
{"add": {"index": "my_index_new", "alias": "my_index_alias"}}
]
}
4. 删除索引(Delete)
DELETE /my_index // 删除单个索引
DELETE /my_index1,my_index2 // 删除多个索引
DELETE /_all // 删除所有索引(高危!需禁用集群配置 action.destructive_requires_name: true)
三、索引的核心类型与设计原则
1. 索引的分类(按使用场景)
| 索引类型 | 特点 | 适用场景 |
|---|---|---|
| 普通索引 | 永久存储,分片固定 | 核心业务数据(如商品、订单) |
| 时间序列索引 | 按时间拆分(如按天 / 月) | 日志、监控数据(ESSI/ILM) |
| 别名(Alias) | 索引的 “软链接”,可指向多个索引 | 业务无感知切换索引、读写分离 |
| 模板(Template) | 预定义 settings/mappings,自动应用到新建索引 | 批量创建同结构索引(如日志索引) |
2. 索引设计核心原则
(1)分片数设计(最核心)
- 主分片大小:建议单分片容量 10-50GB(过大导致查询慢、恢复时间长,过小导致分片过多,集群管理开销大);
- 计算方式:
主分片数 = 总数据量 / 单分片容量(预留 20% 扩容空间); - 示例:总数据量 200GB → 主分片数 = 200 / 30 ≈ 7(取整)。
(2)避免过度分片
- 集群分片总数建议 ≤ 节点数 * 20(如 3 节点集群 ≤ 60 分片);
- 分片过多会导致:集群元数据占用内存高、分片均衡耗时、查询时协调节点开销大。
(3)时间序列数据:按时间拆分索引
-
如日志数据按天创建索引
log-2025-12-01、log-2025-12-02,优势:- 过期数据可直接删除整个索引(比删除文档高效);
- 不同时间段数据可设置不同副本 / 保留策略;
- 结合 ILM(索引生命周期管理)自动化管理(创建→滚动→冻结→删除)。
(4)使用别名简化管理
-
读写分离:别名
my_index_write指向主分片节点,my_index_read指向副本节点; -
平滑升级:重建索引后切换别名,业务无需修改代码;
-
示例:
// 创建别名,指向多个索引(查询时可聚合多个索引数据) PUT /log_alias { "aliases": { "log_alias": {"index": ["log-2025-12-01", "log-2025-12-02"]} } }
四、索引生命周期管理(ILM):自动化运维
ES 提供 ILM 功能,自动管理索引的全生命周期,核心用于时间序列数据:
1. 生命周期阶段
- hot:活跃写入 / 查询,设置副本数、刷新间隔优化性能;
- warm:写入停止,仅查询,可收缩分片、降副本、冻结索引;
- cold:极少查询,可迁移到低性能节点、压缩数据;
- delete:过期后自动删除。
2. 配置示例(按天滚动日志索引)
// 1. 创建生命周期策略
PUT /_ilm/policy/log_policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": { // 滚动条件:大小10GB或创建1天
"max_size": "10gb",
"max_age": "1d"
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": {"number_of_shards": 1}, // 收缩分片为1
"allocate": {"require": {"box_type": "warm"}} // 迁移到warm节点
}
},
"delete": {
"min_age": "30d",
"actions": {"delete": {}}
}
}
}
}
// 2. 创建索引模板,关联策略
PUT /_index_template/log_template
{
"index_patterns": ["log-*"], // 匹配所有log-开头的索引
"template": {
"settings": {
"index.lifecycle.name": "log_policy",
"index.lifecycle.rollover_alias": "log_alias" // 滚动别名
}
}
}
// 3. 创建初始索引(需以-000001结尾)
PUT /log-000001
{
"aliases": {
"log_alias": {"is_write_index": true} // 写入别名指向该索引
}
}
五、索引性能优化
1. 写入性能优化
- 调大刷新间隔:
index.refresh_interval: 5s(批量写入时); - 禁用副本:写入前设
number_of_replicas: 0,写入完成后恢复; - 批量写入:使用
_bulkAPI,单批次大小 5-15MB(避免过大导致超时); - 关闭字段动态映射:
index.mapper.dynamic: false,避免自动推断类型开销。
2. 查询性能优化
- 分片大小合理(10-50GB),避免分片过多 / 过大;
- 字段按需索引:无需查询的字段设
index: false,无需分词的文本设keyword; - 启用字段缓存:对高频排序 / 聚合的字段设
doc_values: true(默认开启); - 使用过滤上下文:查询时用
filter替代must,利用缓存提升性能。
3. 存储优化
- 启用压缩:
index.codec: best_compression(牺牲少量 CPU,降低存储 30%-50%); - 冻结冷索引:
POST /log-2025-11-01/_freeze(冻结后仅只读,大幅降低内存占用); - 清理历史数据:通过 ILM 自动删除或收缩冷索引。
六、常见误区
- 主分片数设置过大 / 过小:过大导致分片容量超标,过小导致集群分片泛滥;
- 滥用动态映射:ES 自动推断类型易出错(如数字识别为 text),建议显式定义映射;
- 忽略索引别名:直接使用索引名,重建索引时需修改业务代码;
- 时间序列数据不拆分:单索引存储全年日志,导致查询慢、删除难;
- 过度追求副本数:副本数越多,写入性能越差(需同步更多数据),建议生产环境 1-2 个副本即可。
总结
ES 索引是数据存储的核心载体,其设计和运维直接决定集群性能和稳定性。核心要点:
- 分片数是索引设计的核心,需根据数据量合理规划(单分片 10-50GB);
- 映射建议显式定义,避免动态映射的坑;
- 时间序列数据优先使用 ILM + 按时间拆分索引,降低运维成本;
- 别名是索引管理的 “利器”,可实现无感知切换、读写分离;
- 性能优化需平衡写入 / 查询 / 存储,按需调整刷新间隔、压缩、分片等配置。