静态设置实战场景举例如下:
设置主分片大小的参数是index.number_of_shards,只在创建索引时生效,不支持动态修改。
默认主分片大小为1,且每个索引的分片数量上限默认为1024。此限制是一个安全限制,可防止索引分片数过多导致集群不稳定。
如果在业务层面扩充节点后确实需要扩展主分片数,该怎么办?
答案:在非业务核心时间通过reindex操作迁移实现。
动态设置的实战场景举例如下:
PUT news_index/_settings
{
"number_of_replicas":3
}
PUT news_index/_settings
{
"refresh_interval":"1s"
}
默认刷新频率参数值为1s,即每秒刷新一次。这1s决定了Elasticsearch是近实时的搜索引擎,而非准实时搜索引擎。如果业务层面对实时性的要求不高,可以考虑将该值调大。因为如果采用1s,则每秒都会生成一个新的分段(关于分段的概念可以参考最后一章),会影响写入性能。
默认情况下,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
需要新增一个分词器为 ik_max_word
的字段 address
,但直接修改映射会导致集群分片重建,且旧数据无法应用新分词器(需重建索引)。
传统方案(无别名)的痛点:
users_v2
并迁移数据,需修改所有客户端代码/配置中的索引名,易遗漏导致线上故障;创建新索引并绑定临时别名:
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
。生产环境双写验证:
users_v1
和 users_v2
(通过别名解耦,代码无需硬编码索引名),users
暂指向 users_v1
,确保线上流量无影响。原子切换别名指向:
POST /_aliases
{
"actions": [
{ "remove": { "index": "users_v1", "alias": "users" } },
{ "add": { "index": "users_v2", "alias": "users" } }
// 可同时删除旧索引(需确保数据迁移完成)
]
}
users_tmp
验证新索引,避免直接操作线上索引;在 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*),通过别名统一管理匹配规则。
我们会发现传统方式不能解决多索引的快速定义和高效管理等问题。因此,索引模板应运而生。
Elasticsearch 7.8及之后版本支持两种定义模板的方式,可简记为普通模板定义方式和组件模板新增/创建方式。
PUT _index_template/ # 模板名称(唯一)
{
"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组件模板即可,改动范围更小、操作更精细化。
模板和索引在应用上的区别是什么?
索引针对的是单一索引,类似MySQL中的一个表。而模板针对一个或多个索引,或者说是针对具有相同表结构的一类索引。
如果想更新映射,那么可以通过更新模板来实现吗?
首先需要建立这样一个认知前提:一旦创建了映射,除几个特定的类型以外,其他类型都不支持更新,除非进行reindex操作。
所以,一旦创建了索引,对索引模板的更新将不会影响该索引。
更新模板仅适用于新创建的索引。更新为动态模板仅会影响索引中的新字段。
在Elasticsearch(基于Lucene实现)中,“分段”(Segment)是底层存储和处理数据的基本单元,本质上是一个不可变的倒排索引文件。以下是具体解释:
refresh
)生成新分段。默认1秒刷新(refresh_interval
):
Elasticsearch默认每1秒将内存缓冲区中的文档写入一个新分段(并开放搜索),这使得数据在写入后1秒内可见,实现“近实时”(Near Real-Time)。
30s
),则每30秒生成一个分段,数据可见延迟增加,但减少分段生成频率。“准实时”与“近实时”的区别:
频繁生成分段的代价:
每次refresh
会:
merge
)操作(长期分段过多时,Elasticsearch会自动合并小分段为大分段,减少搜索时的开销)。调大刷新间隔的优势:
减少分段生成频率,降低I/O和元数据管理开销,提升写入性能,适合对实时性要求不高的场景(如日志分析、离线报表)。
refresh
操作将内存数据写入新分段(默认1秒一次)。