ElasticSearch深入解析(八):索引设置、索引别名、索引模板

一、索引的动态设置、静态设置

  • 索引设置包含两部分核心内容:
    • 静态设置(static index settings),只允许在创建索引时或者针对已关闭的索引进行设置。
    • 指动态设置(dynamic index settings),可以借助更新设置(update settings)的方式进行动态更新,更新后立即生效。

1. 静态设置

静态设置实战场景举例如下:
设置主分片大小的参数是index.number_of_shards,只在创建索引时生效,不支持动态修改。

默认主分片大小为1,且每个索引的分片数量上限默认为1024。此限制是一个安全限制,可防止索引分片数过多导致集群不稳定。

如果在业务层面扩充节点后确实需要扩展主分片数,该怎么办?
答案:在非业务核心时间通过reindex操作迁移实现。​

2. 动态设置

动态设置的实战场景举例如下:

  • 设置副本数参数为index.number_of_replicas,可以动态修改:
PUT news_index/_settings
{
	"number_of_replicas":3
}
  • 设置刷新频率参数为index.refresh_interval,可以动态修改:
PUT news_index/_settings
{
	"refresh_interval":"1s"
}

默认刷新频率参数值为1s,即每秒刷新一次。这1s决定了Elasticsearch是近实时的搜索引擎,而非准实时搜索引擎。如果业务层面对实时性的要求不高,可以考虑将该值调大。因为如果采用1s,则每秒都会生成一个新的分段(关于分段的概念可以参考最后一章),会影响写入性能。

  • max_result_window是Elasticsearch中的一个设置参数,用于控制搜索结果的最大窗口的大小:

默认情况下,max_result_window的值为10000,这意味着在分页搜索时最多可以返回10000条数据。如果每页可显示10条数据,那么最多可以翻到1000页。在某些情况下,可能需要处理比默认值更大的数据集。

在这种情况下,可以通过更新索引设置来动态修改max_result_window的值:

PUT news_index/_settings
{
	"max_result_window":50000
}

上述命令将max_result_window的值设置为50000。此时如果每页显示10条数据,则可以最多翻到5000页。

增大max_result_window的值可能会对Elasticsearch集群的性能产生影响,尤其是在处理大量数据时。因此,在根据实际需求调整此参数时,要权衡性能和查询范围之间的关系。如果需要遍历大量数据,则建议使用scroll API或search_after参数,以更高效地进行处理。

在 Elasticsearch 中,max_result_window参数(默认值为 10000)主要限制的是基于from + size的深度分页查询(即通过from指定偏移量,size指定每页大小)。这种查询方式在偏移量(from)较大时,会导致 Elasticsearch 在每个分片上生成大量中间结果并合并,消耗大量内存和 CPU,甚至引发 OOM(内存溢出)。
而 scroll API 和 search_after 这两种分页方式,设计上避免了max_result_window的直接限制。

二、索引别名

  • 索引别名常见的使用场景:
    • 当需要定期创建新索引(如日志按天 / 月分割),同时保持应用端无需感知索引名称变化时,通过别名指向 “当前有效索引”,实现无缝切换。
    • 索引重建或结构升级:旧索引 users_v1 需升级到 users_v2(如新增字段、调整映射),先通过别名 users 指向 users_v1,应用正常访问,重建完成后,通过原子操作切换别名指向 users_v2,实现无感知迁移。

索引别名只是物理索引的软链接的名称而已,一个索引可以创建多个别名,一个别名也可以指向多个索引。

实战中,很多工程师在开发中后期才发现索引别名的妙处。正如前文所说,别名能进行高效的索引管理,能进行索引数据修改或更新操作并确保用户无感知。

  • 示例场景
    线上索引 users_v1 需要新增一个分词器为 ik_max_word 的字段 address,但直接修改映射会导致集群分片重建,且旧数据无法应用新分词器(需重建索引)。

  • 传统方案(无别名)的痛点

  1. 重建新索引 users_v2 并迁移数据,需修改所有客户端代码/配置中的索引名,易遗漏导致线上故障;
  2. 切换期间需停机或双写,用户体验差。
  • 别名实现无感知升级(步骤)
  1. 创建新索引并绑定临时别名

    PUT /users_v2
    {
      "mappings": {
        "properties": {
          "address": { "type": "text", "analyzer": "ik_max_word" }
        }
      }
    }
    POST /_aliases
    {
      "actions": [
        { "add": { "index": "users_v2", "alias": "users_tmp" } }
      ]
    }
    
    • 开发/测试环境通过 users_tmp 验证新索引逻辑,不影响线上 users_v1
  2. 生产环境双写验证

    • 应用端同时写入 users_v1users_v2(通过别名解耦,代码无需硬编码索引名),
    • 读取时通过别名 users 暂指向 users_v1,确保线上流量无影响。
  3. 原子切换别名指向

    POST /_aliases
    {
      "actions": [
        { "remove": { "index": "users_v1", "alias": "users" } },
        { "add": { "index": "users_v2", "alias": "users" } }
        // 可同时删除旧索引(需确保数据迁移完成)
      ]
    }
    
    • 切换瞬间完成,客户端无感知,无需重启服务或修改配置。
  • 核心价值
  • 风险隔离:通过临时别名 users_tmp 验证新索引,避免直接操作线上索引;
  • 零停机迁移:利用别名的原子操作,实现“热切换”,用户请求始终路由到有效索引。
  1. 从别名检索:

在 Elasticsearch 中,检索时使用索引别名与使用真实索引名的操作完全一致,别名会被透明解析为实际指向的索引(单个或多个)。

# 简单查询
GET /my_alias/_search
{
  "query": { "match_all": {} }
}

# 带过滤的查询
GET /my_alias/_search
{
  "query": { "term": { "status": "active" } }
}

若别名指向多个索引(如 logs_2025_q1 指向 logs-2025-01、logs-2025-02、logs-2025-03),检索时会同时查询所有关联索引:

GET /logs_2025_q1/_search
{
  "query": { "range": { "timestamp": { "gte": "2025-01-01" } } }
}

等价于 GET /logs-2025-01,logs-2025-02,logs-2025-03/_search,但别名简化了索引列表的维护。

别名支持通配符模式(如 logs-*),检索时自动匹配所有符合模式的索引:

# 创建别名匹配2025年4月的所有日志索引
POST /_aliases
{
  "actions": [
    { "add": { "index": "logs-2025-04*", "alias": "april_logs" } }
  ]
}
# 检索时使用别名
GET /april_logs/_search
{ "query": { "term": { "service": "user-center" } } }

避免在 DSL 中硬编码索引模式(如 logs-2025-04*),通过别名统一管理匹配规则。

三、索引模板

  • 两个常见的业务场景问题:
    • 问题1:数据量非常大,需要进行索引生命周期管理,具体要按日期划分索引,且要求多个索引的Mapping一致,而每次手动创建或者脚本创建都很麻烦,怎么办?
    • 问题2:实际业务中应用了多个索引,想让这些索引中相同名字的字段类型完全一致,以便实现跨索引检索,怎么办?

我们会发现传统方式不能解决多索引的快速定义和高效管理等问题。因此,索引模板应运而生。

1. 索引模板的定义

Elasticsearch 7.8及之后版本支持两种定义模板的方式,可简记为普通模板定义方式组件模板新增/创建方式

  • 普通模板定义方式如下所示:
PUT _index_template/<template_name>  # 模板名称(唯一)
{
  "index_patterns": ["logs-*", "metrics-*"],  # 匹配的索引名模式(支持通配符)
  "priority": 100,                            # 模板优先级(高优先级覆盖低优先级)
  "template": {                               # 新索引的配置内容
    "settings": {                             # 索引设置(分片、副本、刷新间隔等)
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "refresh_interval": "30s"
    },
    "mappings": {                             # 字段映射(类型、分词器、动态模板等)
      "dynamic": "strict",                     # 严格模式(禁止自动添加未定义字段)
      "properties": {
        "@timestamp": { "type": "date" },      # 时间字段(必选,用于时序数据)
        "message": { 
          "type": "text", 
          "analyzer": "ik_max_word",            # 中文分词器(需提前安装)
          "fields": { "keyword": { "type": "keyword" } }  # 同时存储keyword子字段
        }
      }
    },
    "aliases": {                              # 为新索引自动绑定别名
      "current_logs": {}                       # 别名指向新索引(无额外配置)
    }
  },
  "composed_of": ["ilm_policy_template"]      # 组合其他组件模板(可选,8.x+ 支持)
}

而组件模板的核心在于将原有普通模板定义的mappings、settings等以组件的方式分隔,以便最小化更新模板。

  • 组件模板定义方式如下所示:

在这里插入图片描述
在这里插入图片描述

由上可知,模板名称为mydata_template,包含两个核心组件——component_mapping_template、component_settings_template。component_mapping_template组件模板实现了映射的定义,component_settings_template实现了设置和别名的定义。

当业务层面需要更新映射时,只需要更新component_mapping_template组件模板即可,改动范围更小、操作更精细化。

2. 索引模板应用的常见问题

模板和索引在应用上的区别是什么?

索引针对的是单一索引,类似MySQL中的一个表。而模板针对一个或多个索引,或者说是针对具有相同表结构的一类索引。

如果想更新映射,那么可以通过更新模板来实现吗?

首先需要建立这样一个认知前提:一旦创建了映射,除几个特定的类型以外,其他类型都不支持更新,除非进行reindex操作。

所以,一旦创建了索引,对索引模板的更新将不会影响该索引。

更新模板仅适用于新创建的索引。更新为动态模板仅会影响索引中的新字段。

分段

在Elasticsearch(基于Lucene实现)中,“分段”(Segment)是底层存储和处理数据的基本单元,本质上是一个不可变的倒排索引文件。以下是具体解释:

分段的本质与作用

  • 倒排索引载体:每个分段存储一组文档的倒排索引(关键词到文档的映射),是Lucene实现快速搜索的核心数据结构。
  • 独立搜索单元:分段一旦生成就不可修改,可独立被搜索,多个分段的搜索结果会在查询时合并。
  • 写入过程的中间产物:文档写入时不会直接写入磁盘上的主索引,而是先存入内存缓冲区,通过定期刷新(refresh)生成新分段。

分段与“近实时”机制的关系

  • 默认1秒刷新(refresh_interval
    Elasticsearch默认每1秒将内存缓冲区中的文档写入一个新分段(并开放搜索),这使得数据在写入后1秒内可见,实现“近实时”(Near Real-Time)。

    • 若调大该值(如30s),则每30秒生成一个分段,数据可见延迟增加,但减少分段生成频率。
  • “准实时”与“近实时”的区别

    • 准实时:数据可见延迟较长(如分钟级),分段生成频率低。
    • 近实时:通过高频刷新(1秒)缩短延迟,但代价是分段数量增加。

分段对写入性能的影响

  • 频繁生成分段的代价
    每次refresh会:

    1. 将内存数据写入分段文件(磁盘I/O);
    2. 生成新的分段元数据(如文件句柄、索引结构);
    3. 可能触发后续的分段合并(merge)操作(长期分段过多时,Elasticsearch会自动合并小分段为大分段,减少搜索时的开销)。
      这些操作在高写入负载下会消耗CPU、磁盘I/O和内存资源,降低写入吞吐量。
  • 调大刷新间隔的优势
    减少分段生成频率,降低I/O和元数据管理开销,提升写入性能,适合对实时性要求不高的场景(如日志分析、离线报表)。

分段的生命周期

  • 生成:通过refresh操作将内存数据写入新分段(默认1秒一次)。
  • 存在:分段不可变,可被搜索,直到被合并或删除。
  • 合并:Elasticsearch后台定期合并小分段为大分段,减少分段数量,提升搜索效率(合并过程会释放旧分段资源)。
  • 删除:当文档被删除时,分段不会立即修改,而是记录“删除标记”,合并时才真正移除被删除的文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值