概述

官方文档:https://www.elastic.co/docs/manage-data/data-store/index-basics

索引是Elasticsearch中的基本存储单元,类似于MySql数据库中的表,包含一堆有相似结构的文档数据,在Elasticsearch可以创建多个索引。

tips:

每个索引默认有5个主分片,1个副本分片,其中的主分片和副本分片的作用,我们下面讲解。

添加至索引中的数据,会被近实时(1秒内)的被搜索(这里不是立即可以被检索)

近实时被搜索如何理解?下面我们会仔细讲解,参考文档:https://www.elastic.co/docs/manage-data/data-store/near-real-time-search

索引的组成

逻辑层面

从逻辑层面来看,索引是由下面几个部分组成:

  • 分片

    • 索引的逻辑拆分单元,每个分片是一个独立的 Lucene 索引
    • 主分片(Primary Shards)负责数据写入和读取,副本分片(Replica Shards)用于容错和负载均衡
    • 分片数量在索引创建时指定,默认 5 个主分片,1个副本分片,可通过设置调整

设置分片示例

PUT /my_index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
  • 映射(Mapping)

    • 定义索引中字段,字段的类型、分词器、存储方式等元数据
    • 支持动态映射(自动推断字段类型)和手动映射(精确控制字段行为)

映射示例:

{
"mappings": {
"properties": {
"title": { "type": "text", "analyzer": "ik_max_word" },
"tags": { "type": "keyword" },
"create_time": { "type": "date" }
}
}
}
  • 文档(Document)

    • 索引中真实的数据记录,类似mysql表中的行数据
    • 索引的最小数据单元,以 JSON 格式存储,包含多个字段(Fields)
    • 每个文档有唯一标识符(ID),可自动生成或手动指定

示例文档记录

{
"_index": "my-first-elasticsearch-index",
"_id": "DyFpo5EBxE8fzbb95DOa",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith",
"info": {
"bio": "Eco-warrior and defender of the weak",
"age": 25,
"interests": [
"dolphins",
"whales"
]
},
"join_date": "2024/05/01"
}
}

物理层面

ES 索引的底层基于 Lucene,其物理存储由以下部分构成:

  • Lucene 分段(Segments)

    • 索引的物理存储单元,每个分段是一个独立的倒排索引
    • 分段由 Refresh 操作生成,包含文档的索引数据和元数据
    • 分段特性:
      • 不可变(Immutable),生成后无法修改,保证搜索时的数据一致性
      • 后台自动合并(Merge),减少分段数量,优化搜索性能
  • 倒排索引(Inverted Index)
    • Lucene 的核心数据结构,是 ES 快速检索的基础
    • 倒排索引将 “文档 - 词语” 的正向关系转换为 “词语 - 文档列表” 的反向关系

结构示例:

词语(Term) | 文档ID列表(Postings List)
-----------|---------------------------
Elasticsearch | [1, 3, 5]
搜索引擎 | [1, 2, 4]
分布式 | [1, 3, 4]
  • 索引文件(Index Files)

    • 每个 Lucene 分段包含多个索引文件,常见类型:

      • *.nvd:存储文档字段值
      • *.nvm:字段值的元数据
      • *.tim:记录词语(Term)的字典和频率
      • *.doc:文档偏移量索引
      • *.pos:词语在文档中的位置信息(用于短语搜索)
      • *.dim:分段元数据(如创建时间、版本等)
  • 事务日志(Translog)

    • 记录所有未持久化的索引操作,确保数据不丢失
    • 存储路径:data/<cluster_name>/nodes/<node_id>/indices/<index_uuid>/translog
    • 作用:
      • 保障 ES 重启后数据恢复
      • 支持增量恢复(Incremental Recovery)

索引分片的作用

主分片

主分片是 Elasticsearch(ES)索引数据存储的基础单元。也是实现ES分布式高可用的基石,主分片在创建索引时通过number_of_shards指定,默认是5个主分片,主分片的数量可以根据主节点的数量来进行设置。

常规业务场景下(数据量中等,单分片≤50GB),每个节点的分片可以设置成1-2个,例如你的主节点有3个,在每个节点的资源规格都一样的情况下,那么你的主分片可以设置为3个或者6个

大数据量场景下(单分片 50GB100GB,总数据量≤600GB),每个节点的分片可以设置成34个,例如你的主节点有3个,在每个节点的资源规格都一样的情况下,那么你的主分片可以设置为9个或者12个

主分片经过设置之后是不可更改的,所以在设置主分片时需要经过慎重的考虑。

其主要作用有以下几点:

  • 每个索引被拆分为多个主分片(默认 5 个),每个主分片是一个独立的 Lucene 索引,负责存储索引的部分文档数据,当执行搜索、更新、删除等操作时,请求会被分发到相关主分片上执行,确保数据操作的直接性和高效性。

  • 主分片是数据写入的唯一入口:所有文档的创建、更新、删除操作都首先在主分片上完成,再同步到副本分片,主分片维护着文档的最新版本和元数据(如版本号、路由信息),确保集群内数据的一致性。

  • 通过增加主分片数量(创建索引时指定),可以将数据分散到更多节点,提升集群的存储容量和并发处理能力。每个主分片可独立分配到不同节点,实现负载均衡(如通过 ES 的分片分配机制自动调整)。

副本分片

副本分片是主分片的镜像拷贝,主要为集群提供可靠性、可用性和性能优化能力。副本分片占用与主分片相同的存储空间,增加副本会提高内存和磁盘使用量,副本分片在创建索引时通过number_of_replicas指定,默认值是1。

副本分片设置之后是可以修改的,如下:

PUT /your_index/_settings
{
"number_of_replicas": 2 // 设置副本数为2
}

副本分片的作用如下:

  • 当某个节点故障或主分片所在节点不可用时,副本分片会被提升为新的主分片(通过 ES 的自动故障转移机制),确保服务不中断,每个副本分片与主分片分布在不同节点(默认策略),避免单点故障(如节点硬件故障、网络分区)导致数据丢失

  • 副本分片可处理读请求(如搜索、获取文档),分担主分片的查询压力,尤其在高并发场景下显著提升集群吞吐量,同一索引的副本分片越多,可并行处理的读请求越多(如每个副本分片可独立响应查询)。

  • 副本分片是数据的冗余存储,即使部分节点损坏,仍可通过其他节点的副本恢复完整数据(无需依赖外部备份),可通过调整副本数量(默认 1 个)平衡可用性和资源消耗(每个副本占用与主分片相同的存储空间)。

修改副本分片的注意事项

  • 注意资源消耗

    • 每个副本分片占用与主分片相同的存储空间,增加副本会提高内存和磁盘使用量。
    • 例如5 主分片 ×2 副本 = 15 个分片,需预留相应存储和 JVM 堆内存。
  • 注意性能影响
    • 增加副本可提升读性能(更多分片可并行处理查询),但修改期间会产生网络流量(复制数据),可能短暂影响集群性能。
    • 建议在低峰期执行大规模副本调整。
  • 故障转移能力
    • 至少保留 1 个副本以保证高可用(允许 1 个节点故障)。
    • 若需容忍 N 个节点故障,副本数应≥N。
  • 集群状态监控
    • 修改过程中通过GET /_cluster/health监控集群状态,确保status为green或yellow(red表示有未分配的主分片)

副本分片和主分片的数量对应关系

当主分片设置成3,副本分片设置成1时,那么一共会有6个分片存在集群中,副本分片的1是将对应的3个主分片分别copy一份在不同的节点中。

索引的近实时性

官方文档:https://www.elastic.co/docs/manage-data/data-store/near-real-time-search

近实时性是指当数据写入至ES的索引中,需要一定时间(官方描述的是1秒内)才能被检索到,这个可以通过下面的参数设置

# 索引创建时设置refresh_interval为500ms
PUT /my_index
{
"settings": {
"refresh_interval": "500ms" # 默认1000ms,也就是1秒
}
}

refresh_interval参数并不是设置的越小越好,当值为0时,会禁用自动 Refresh,仍需手动触发 Refresh 才能让文档可搜索,这会引入人为延迟(人为操作,延迟可能更大)。

Refesh机制

Refresh 机制是控制近实时性的关键

  • 默认 Refresh 间隔:ES 默认每 1 秒执行一次 Refresh 操作,这就是 “1 秒近实时” 的来源
  • 手动触发 Refresh:可通过 API 强制刷新,实现更低延迟(如POST /index/_refresh)
  • 性能与实时性的权衡:缩短 Refresh 间隔会提高实时性,但会增加 IO 开销;延长间隔则反之

为什么ES不是 “完全实时”的?

  • Refresh 间隔的存在:即使将refresh_interval设为 0(禁用自动 Refresh),仍需手动触发 Refresh 才能让文档可搜索,这会引入人为延迟。
  • 写入流程的固有延迟:文档从写入到生成分段需要经历内存缓冲区处理,无法做到完全实时(如数据库的实时查询)。
  • 设计权衡:ES 牺牲极小的实时性(1 秒)换取高性能和分布式架构的稳定性,这是分布式搜索系统的典型设计。

索引的管理

ES的索引类似类似数据库中的表,管理ES的索引需要通过ES的API来进行管理。索引的API主要有以下

创建索引

API

PUT /{index}
{
"aliases": { ... }, # 指定索引别名
"settings": { ... }, # 指定索引的设置
"mappings": { ... } # 指定映射
}

参数说明:

index:索引的名称,需要遵循以下规则:

  • 仅限小写字母
  • 不能包含\、/、 *、?、"、<、>、|、#以及空格符等特殊符号
  • 从7.0版本开始不再包含冒号
  • 不能以-、_或+开头
  • 不能超过255个字节(注意它是字节,因此多字节字符将计入255个限制)

aliases:索引别名(Aliases) 是指向一个或多个索引的逻辑名称,可用于简化查询、实现读写分离或索引滚动等场景

settings:索引的配置参数,如分片数、副本数、刷新间隔等。常用的配置参数为:

  • number_of_shards:指定索引分片
  • number_of_replicas:指定副本数
  • refresh_interval:指定刷新时间,单位秒
  • auto_expand_replicas:自动调整副本数(根据节点数)
  • indices.memory.index_buffer_size:索引缓冲区占堆内存的比例(默认10%)
  • index.translog.durability:异步刷新事务日志(默认sync)
  • index.translog.flush_threshold_size:事务日志刷新阈值
  • index.queries.cache.enabled:启用查询结果缓存(默认true)
  • indices.queries.cache.size:缓存占堆内存比例
  • indices.fielddata.cache.size:字段数据缓存大小
  • index.priority:控制索引在恢复和分片分配时的优先级
  • index.routing.allocation.include.tag:强制分片分配到特定节点,包含特定标签的节点
  • index.routing.allocation.exclude._name:强制分片分配到特定节点,排除特定节点
  • index.blocks.write:true设置索引只读
  • index.hidden:true设置索引隐藏,不显示在_cat/indices
  • index.max_result_window:调整深度分页限制,默认10000,慎用!推荐用scroll或search_after

mappings:定义索引字段的数据类型和索引方式。后续会单独讲解mappings

实战:创建第一个索引

可以进入kibana进行创建:

示例:

# 创建请求
PUT index_test01
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "1s"
}
} # 预期返回
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "index_test01"
}

查看索引

查看所有的索引

示例:

# 请求接口
GET /_cat/indices?v&s=index # 预期返回
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .apm-agent-configuration KC2krPV1Q6On8zLG-2Ap6g 1 1 0 0 454b 227b
green open .apm-custom-link fW3LcrktTOGTDKvglhgODQ 1 1 0 0 454b 227b
green open .kibana_7.17.26_001 Bv6ZMZL6STaho_Phwbrv1w 1 1 691 16 5.3mb 2.8mb
green open .kibana_task_manager_7.17.26_001 0wrV35RzTWahe5vAUJKVow 1 1 17 25815 5.8mb 2.8mb
green open index_test01 TRTmGpiNRuC1wZY49Wt_aA 3 1 0 0 1.3kb 681b

返回字段说明:

  • health:索引的健康程度,green表示所有主分片和副本分片都正常运行,red表示至少有一个主分片未分配(数据可能丢失),yellow表示主分片正常,但至少有一个副本分片未分配
  • status:open表示索引可正常读写,close表示索引已关闭,不可访问
  • index:索引名称,以 . 开头的通常是系统索引,如 Kibana、APM 等组件创建的索引
  • uuid:索引的唯一标识符(用于内部识别,不可修改)
  • pri:主分片数量(创建索引时指定,不可动态修改)
  • rep:主分片的副本数量(可动态调整)
  • docs.count:索引中的文档总数
  • docs.deleted:已标记删除但尚未物理删除的文档数(段合并后会清理)
  • store.size:索引的总存储大小(包括主分片和所有副本)
  • pri.store.size:主分片的存储大小(不包括副本)

查看指定的索引

api:GET /{index-name}

示例:

# 请求
GET /index_test01 # 预期返回
{
"index_test01" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"refresh_interval" : "1s", # 刷新时间
"number_of_shards" : "3", # 主分片数量
"provided_name" : "index_test01", # 索引名称
"creation_date" : "1750482108424", # 创建时间
"number_of_replicas" : "1", # 副本数量
"uuid" : "TRTmGpiNRuC1wZY49Wt_aA", # uuid,唯一标识符
"version" : {
"created" : "7172699"
}
}
}
}
}

其它查询的api

API 路径 功能描述 示例
GET /{index}/_settings 获取索引设置 GET /products/_settings
GET /{index}/_mapping 获取索引映射 GET /products/_mapping
GET /{index}/_alias 获取索引别名 GET /products/_alias
GET /{index}/_stats 获取索引统计信息 GET /products/_stats
GET /{index}/_shards 获取分片状态 GET /products/_shards
GET /_cluster/health 集群健康状态 GET /_cluster/health
GET /_cluster/health/{index} 特定索引健康状态 GET /_cluster/health/products
GET /{index}/_recovery 恢复进度 GET /products/_recovery
GET /{index}/_segments 段信息 GET /products/_segments
GET /{index}/_field_usage_stats 字段使用统计 GET /products/_field_usage_stats

修改索引

在 Elasticsearch 中,修改索引设置的 API 允许动态调整索引的配置参数(如副本数、刷新间隔等)

动态修改索引设置(运行时生效)

修改单个或多个设置

示例:

PUT /{index}/_settings
{
"settings": {
"setting_name_1": "value_1",
"setting_name_2": "value_2",
...
}
}

修改副本数

# 请求
PUT /index_test01/_settings
{
"settings": {
"number_of_replicas": 2
}
} # 预期返回
{
"acknowledged" : true
} # 查看一下
GET /index_test01/_settings
{
"index_test01" : {
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"refresh_interval" : "1s",
"number_of_shards" : "3",
"provided_name" : "index_test01",
"creation_date" : "1750482108424",
"number_of_replicas" : "2",
"uuid" : "TRTmGpiNRuC1wZY49Wt_aA",
"version" : {
"created" : "7172699"
}
}
}
}
}

支持动态修改的参数

设置名称 说明 示例值
number_of_replicas 副本数 2
refresh_interval 刷新间隔(控制新文档可见性) 30s, -1(禁用自动刷新)
index.search.slowlog.threshold.query.warn 查询慢日志阈值(警告级别) 10s
index.max_result_window 分页最大结果数(深度分页风险) 100000
index.blocks.write 禁止写入(只读模式) true
index.routing.allocation.exclude._name 排除特定节点 node1,node2
index.priority 恢复优先级 10

静态设置参数(需关闭索引后修改)

某些设置(如主分片数)必须在索引关闭后才能修改:

# 关闭索引
POST /{index}/_close # 修改静态设置
PUT /{index}/_settings
{
"settings": {
"number_of_shards": 10 # 仅示例,生产环境谨慎修改
}
}

删除索引(谨慎操作,可以使用关闭索引替代)

在 Elasticsearch 中,删除索引是一个不可逆操作,会永久移除索引及其所有数据

删除单个索引

api:DELETE /{index}

示例:

# 请求
DELETE /index_test01 # 预期返回
{
"acknowledged" : true
} # 验证索引是否存在
HEAD /index_test01
# 预期返回,404表示已经删除
{"statusCode":404,"error":"Not Found","message":"404 - Not Found"}

删除多个索引

使用逗号分隔多个索引名,或通配符匹配:

示例:

DELETE /{index1},{index2},...

# 通配符,删除所有以logs-开头的索引
DELETE /logs-*

删除所有索引(谨慎操作)

警告:此操作会删除集群中所有索引,生产环境中禁用!

安全措施:部分集群配置了action.destructive_requires_name为true,禁止通过通配符删除所有索引。

DELETE /_all
DELETE /*

索引的其它操作

  • 关闭索引:POST /{index}/_close,关闭索引,使其不能进行读写操作,以节省资源。
  • 打开索引:POST /{index}/_open,打开已关闭的索引,恢复其读写功能。
  • 收缩索引:POST /{index}/_shrink/{target_index},将索引收缩为指定的目标索引,可减少分片数量。
  • 拆分索引:POST /{index}/_split/{target_index},将索引拆分为多个新的索引。
  • 克隆索引:POST /{index}/_clone/{target_index},克隆一个现有的索引到新的索引。
  • 索引滚动:POST /{alias}/_rollover,用于将数据从一个索引滚动到另一个索引,常用于按时间滚动的索引场景。
  • 冻结索引:POST /{index}/_freeze,冻结索引,使其数据不可变,以节省内存和提高查询性能。
  • 解冻索引:POST /{index}/_unfreeze,解冻已冻结的索引,恢复其可写状态。
  • 解析索引:GET /_resolve_index/{index},解析索引的名称,返回其真实的索引名称和相关信息。
  • 检查索引是否存在:HEAD /{index},通过请求的响应状态码判断索引是否存在,200 表示存在,404 表示不存在。

浅谈ElasticSearch索引的更多相关文章

  1. 浅谈MySQL索引背后的数据结构及算法

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  2. 浅谈MySQL索引背后的数据结构及算法(转载)

    转自:http://blogread.cn/it/article/4088?f=wb1 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储 ...

  3. 浅谈MySQL索引背后的数据结构及算法【转】

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  4. 搜索浅谈(Elasticsearch和Lucene4分享)

    刚刚过去的双11,真是给线下运营商好好上了一课.当今的互联网真是炙手可热,大家对互联网的热情是如此之高.相信电商之间的竞争将更加的激烈和残酷,不过,搜索,作为用户体验很重要的一点,各大电商也做的越来越 ...

  5. 浅谈elasticsearch 集群

    elasticsearch 集群 摘要: elasticsearch 集群 搭建elasticsearch的集群 现在假设我们有3台es机器,想要把他们搭建成为一个集群 基本配置 每个节点都要进行这样 ...

  6. 浅谈Mysql索引

    文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 我们都知道,数据库索引可以帮助我们更加快速的找出符合的数据,但是如果不使用索引,Mysql则会从第一条开始查询 ...

  7. 浅谈sql索引

    索引是什么 假如你手上有一个你公司的客户表,老板说找什么客户你就得帮他找出来. 客户不多的时候,你拿着手指一行一行滑,费不了多少时间就能找到. 后来公司做大了,客户越来越多,好几页的客户,你发现,一行 ...

  8. 浅谈B+树索引的分裂优化(转)

    http://www.tamabc.com/article/85038.html 从MySQL Bug#67718浅谈B+树索引的分裂优化   原文链接:http://hedengcheng.com/ ...

  9. 浅谈SQL优化入门:3、利用索引

    0.写在前面的话 关于索引的内容本来是想写的,大概收集了下资料,发现并没有想象中的简单,又不想总结了,纠结了一下,决定就大概写点浅显的,好吧,就是懒,先挖个浅坑,以后再挖深一点.最基本的使用很简单,直 ...

  10. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

随机推荐

  1. 使用 vscode-jest 插件

    vscode-jest [error] Abort jest session: Not able to auto detect a valid jest command: multiple candi ...

  2. Spring Cloud Gateway限流极速部署:3步搞定,秒级防护微服务!

    Spring Cloud Gateway限流极速部署:3步搞定,秒级防护微服务! 想要快速为Spring Cloud Gateway集成限流功能?本文提供最简方案,无需复杂配置,三步即可完成!通过内置 ...

  3. RabbitMQ 延迟任务(限时订单) 思路

    一.场景 我们经常会碰见,一个需求就是,发送一条指令(消息),延迟一段时间执行,比如说常见的淘宝当下了一个订单后,订单支付时间为半个小时,如果半个小时没有支付,则关闭该订单.当然实现的方式有几种,今天 ...

  4. 学习unigui【28】UniGUI接收POST/GET

    小儿科问题,直接上流程代码: 1 procedure TUniServerModule.UniGUIServerModuleHTTPCommand( 2 ARequestInfo: TIdHTTPRe ...

  5. 可横竖控制的Text bg Control

    using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [RequireComponent(typeof(Co ...

  6. 在 ASP.NET Core 中编写高性能 Web API 的4个小技巧

    Web API 通常用来与外部模块进行通信.发送和接收数据,作为后端开发人员,应该把写出高性能的应用作为目标. 下面 4 个技巧是我在编写 Web API 的小技巧. 1 .大量数据使用分页查询 接口 ...

  7. markdown文本编辑器--核心功能(解析和渲染)

    开源项目地址 GitHub 开源地址(YtyMark-java) 欢迎提交 PR.Issue.Star ️! 1. 简述 YtyMark-java项目分为两大模块: UI界面(ytyedit-mark ...

  8. Full GC 频率优化实战

    作者:vivo 互联网服务器团队- Li Gang 本文介绍了游戏业务使用MAT和GC日志等工具对 Full GC频率进行优化的过程. 一.背景 游戏业务面对用户端的某个工程,每天Full GC频率达 ...

  9. 【笔记】Excel 2021|VBA删除数组中的一个元素、循环时删除一行、选择一列删除指定一行

    主要问题是循环的时候删除一行比较麻烦,因为删除了一行后,循环仍然直接访问后一行,会导致一定的异常. 文章目录 选择一列,删除指定一行 删除数组中的一个元素 方法1:利用动态数组,在循环中条件判断删除 ...

  10. Java 数据库开发总结

    数据库连接.设计以及备份技巧集锦 JDBC操作各种数据库经验技巧集萃 Java 数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成.JDBC 为工具/数据库开发人员提供了一个标准的  ...