通过API命令管理Elasticsearch索引的终极指南
通过这份终极API命令指南,掌握Elasticsearch索引管理。学习如何使用`PUT`精心创建具有自定义映射和设置的索引,使用`GET`全面查看其配置和详细信息,以及使用`DELETE`安全删除不必要的索引。本文提供实用示例、最佳实践和重要警告,帮助您有效控制Elasticsearch中的数据生命周期,实现最佳性能和资源管理。
通过API命令管理Elasticsearch索引的终极指南
通过API管理Elasticsearch索引是日常操作,但也是许多代价高昂的错误发生之处。一个错误的映射可能迫使你重新索引。一个通配符删除可能删除超出你预期的内容。一个在开发环境中合理的副本设置,可能在部署后让生产环境处于黄色状态。
Elasticsearch索引不仅仅是一个JSON文档的桶。它包含映射、设置、别名、分片数量、副本数量、分析器和生命周期行为。你不需要记住每一个API来很好地管理它,但你需要一个谨慎的例行程序:有意图地创建索引,检查Elasticsearch实际创建了什么,只更新可以安全更改的设置,并在有保护措施的情况下进行删除。
下面的示例使用Kibana Dev Tools风格的请求。如果你更喜欢curl,相同的路径和JSON主体适用于http://host:9200。
索引包含什么
索引是文档的逻辑命名空间。在底层,主分片保存数据,副本分片复制数据以实现冗余和搜索能力。确切的分片和副本默认行为可能因Elasticsearch版本和部署模式而异,所以不要依赖记忆。检查你自己集群中的设置。
你最常检查的三个部分是:
settings,例如number_of_shards、number_of_replicas、refresh_interval和分析配置。mappings,定义字段类型,如keyword、text、date、long、double、boolean、ip以及嵌套/对象字段。aliases,允许应用程序使用一个稳定的名称,而你可以在背后交换真实的底层索引。
一个好的索引API工作流程在第一个文档被索引之前就开始了。动态映射对于探索很有用,但生产环境的索引应该为重要字段提供显式映射。如果user_id被意外映射为text,聚合和精确过滤会变得棘手。如果时间戳被映射为text,时间范围查询的行为将不像日期查询。这些错误是可以修复的,但通常需要创建一个新索引并重新索引。
创建一个简单的索引
最小的创建请求是:
PUT /my_first_index
如果索引被创建,Elasticsearch会返回一个确认:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "my_first_index"
}
这对于一个临时索引来说没问题。对于真实数据,使用你期望的设置和映射创建索引,而不是让前几个文档定义其形状。
创建带有映射和设置的索引
这是一个实用的products索引。它支持对名称和描述进行全文搜索,对ID和类别进行精确过滤,日期排序,数字范围过滤,以及简单的可用性检查。
PUT /products-v1
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s"
},
"mappings": {
"dynamic": "strict",
"properties": {
"product_id": { "type": "keyword" },
"sku": { "type": "keyword" },
"name": {
"type": "text",
"fields": {
"raw": { "type": "keyword", "ignore_above": 256 }
}
},
"description": { "type": "text" },
"category": { "type": "keyword" },
"price": { "type": "scaled_float", "scaling_factor": 100 },
"stock": { "type": "integer" },
"available": { "type": "boolean" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" }
}
}
}
这里的一些选择是经过深思熟虑的。product_id、sku和category是keyword类型,因为你通常会围绕精确值进行过滤、聚合或连接应用程序行为。name是text类型用于搜索,并带有一个name.raw关键字子字段用于排序和精确匹配。price使用scaled_float,这样价格可以存储为类似美分的缩放值,而不是二进制浮点近似值。dynamic: strict拒绝未知字段,这在不良生产者数据应该大声失败时很有用。
不要盲目复制分片数量。三个主分片对于一个小的索引可能太多,对于一个大的索引可能太少。分片数量在创建后很难更改,除非进行收缩、拆分或重新索引式的迁移,所以要根据预期的数据量、保留期和节点数量来确定其大小。
创建后检查索引
始终验证Elasticsearch接受了什么:
GET /products-v1
这将返回设置、映射和别名。对于有针对性的检查,使用更窄的端点:
GET /products-v1/_mapping
GET /products-v1/_settings
GET /products-v1/_alias
要获得许多索引的紧凑命令行视图:
GET /_cat/indices/products-*?v
有用的列包括健康状态、状态、主分片数量、副本数量、文档数量、已删除文档数量和存储大小。_cat API是为人类设计的。对于脚本,请使用JSON API。
如果你要检查某个字段是否映射正确,请使用:
GET /products-v1/_mapping/field/price
GET /products-v1/_mapping/field/name.raw
这比滚动浏览大型映射要快得多。
安全地更新索引设置
有些设置是动态的。副本数量是常见的一个:
PUT /products-v1/_settings
{
"index": {
"number_of_replicas": 2
}
}
如果你没有足够合适的节点来放置副本,这可能会使绿色集群变成黄色。例如,一个主分片加上两个副本需要三个不同的位置来放置副本。分配感知规则可能会使要求更严格。
refresh_interval是另一个你可能会在批量加载期间更改的设置:
PUT /products-v1/_settings
{
"index": {
"refresh_interval": "30s"
}
}
更长的刷新间隔可以减少索引开销,但新索引的文档对搜索的可见性会变慢。对于批量回填,团队通常会增加或临时禁用刷新,加载数据,然后恢复正常的间隔并刷新一次:
POST /products-v1/_refresh
有些设置是静态的。number_of_shards不能在打开的现有索引上更改。如果你发现主分片数量错误,请计划一个新索引和迁移。
诚实地更改映射
你可以向映射添加新字段:
PUT /products-v1/_mapping
{
"properties": {
"brand": { "type": "keyword" }
}
}
你通常不能就地更改现有字段的类型。如果price已经是text类型,这不会将旧值变成有用的数字字段。创建一个具有正确映射的新索引并重新索引:
POST /_reindex
{
"source": { "index": "products-v1" },
"dest": { "index": "products-v2" }
}
对于生产迁移,使用别名,这样应用程序就不需要知道物理索引版本。
使用别名实现更安全的应用程序访问
将别名指向第一个版本:
POST /_aliases
{
"actions": [
{ "add": { "index": "products-v1", "alias": "products" } }
]
}
你的应用程序从products读取。稍后,创建products-v2,重新索引数据,测试它,然后原子地交换别名:
POST /_aliases
{
"actions": [
{ "remove": { "index": "products-v1", "alias": "products" } },
{ "add": { "index": "products-v2", "alias": "products" } }
]
}
对于写入量大的系统,使用写入别名并明确指定is_write_index:
POST /_aliases
{
"actions": [
{ "add": { "index": "products-v2", "alias": "products-write", "is_write_index": true } }
]
}
别名是避免将索引版本硬编码到服务中的最简单方法之一。
小心地列出和搜索索引名称
要检查多个索引:
GET /products-v1,products-v2/_settings
GET /products-*/_mapping
GET /_cat/indices/products-*?v&s=index
在大型集群上要小心使用宽泛的通配符。GET /*或GET /_all可能会产生巨大的响应,并且根据版本、设置和请求选项,可能包括系统或隐藏索引。优先使用狭窄的模式,如logs-prod-*或products-*。
要从脚本检查索引是否存在,请使用HEAD:
HEAD /products-v1
200表示存在。404表示不存在。
在保护措施下删除索引
删除很简单:
DELETE /products-v1
操作风险不在于语法。风险在于删除了错误的索引或在快照完成之前删除。
在删除之前,列出模式完全匹配的内容:
GET /_cat/indices/products-old-*?v&s=index
如果输出正确且数据可恢复或不再需要,则删除相同的模式:
DELETE /products-old-*
许多集群使用action.destructive_requires_name限制破坏性的通配符操作。这是一个很好的安全设置,因为它会阻止宽泛的删除,例如DELETE /*,除非需要显式名称。即使有这种保护,也要将删除操作视为生产变更:确认索引模式,确认快照,并确认调用者具有正确的权限。
对时间序列数据优先使用生命周期策略
手动删除对于一次性清理是可以接受的。对于日志、指标、跟踪和其他时间序列数据,请在适当的地方使用索引生命周期管理或数据流。生命周期策略可以在索引达到年龄或大小目标时滚动它,将旧数据移动到不同的层,并在保留期到期后删除它。
这很重要,因为手动清理往往在最糟糕的时候失败。有人忘记了它,磁盘满了,洪水级水位标记使索引变为只读,然后团队在压力下进行清理。生命周期策略将保留变成配置,而不是日历提醒。
一个简单的日常例行程序
对于生产集群,一个实用的索引管理例行程序如下所示:
检查健康状态:
GET /_cluster/health
按模式列出索引:
GET /_cat/indices/logs-*?v&s=store.size:desc
检查可疑的设置:
GET /logs-prod-2026.05.24/_settings
在从应用程序发布添加新字段之前检查映射:
GET /logs-prod-2026.05.24/_mapping
在迁移前后确认别名:
GET /_cat/aliases/products*?v
这不是什么光鲜的工作,但它能及早发现许多问题:错误的副本数量、意外的动态字段、过时的别名以及本应过期但未过期的旧索引。
要避免的常见错误
不要让开发默认值成为生产架构。单节点集群、零副本和动态映射对于演示可能没问题。但它们不是恢复计划。
不要在心里更改映射并假设Elasticsearch同意。检查实际的映射。
不要在没有先列出匹配的索引的情况下使用通配符删除。
不要在没有足够的数据节点和可用区来放置它们的情况下设置高副本数量。
不要跳过应用程序依赖的索引的别名。如果应用程序已经与别名通信,第一次迁移将会容易得多。
良好的索引管理主要是纪律性的重复。有意图地创建,检查存在的内容,使用别名进行迁移,自动化保留,并使破坏性操作变得乏味地明确。
模板比一次性创建更重要
如果你重复创建相同类型的索引,不要依赖手动的PUT /index-name调用。使用索引模板或可组合模板,以便新索引自动接收正确的映射、设置、别名和生命周期策略。
日志平台是经典的例子。如果logs-web-2026.05.24有一个正确的@timestamp映射,但明天的索引是由第一个文档动态创建的,一个格式错误的事件可能会错误地映射一个字段。这个错误可能直到仪表板失败或聚合消失时才显现出来。模板可以防止这种偏差。
一个简单的模板可能会为未来的索引定义一个模式、设置和映射:
PUT /_index_template/logs_web_template
{
"index_patterns": ["logs-web-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"service": { "type": "keyword" },
"level": { "type": "keyword" },
"message": { "type": "text" },
"trace_id": { "type": "keyword" }
}
}
}
}
模板也更容易在代码中审查。将它们放入版本控制,通过与应用更改相同的路径部署它们,并在滚动创建下一个底层索引之前进行测试。
在不惊动应用程序的情况下重新索引
最干净的索引迁移通常是:创建一个新的版本化索引,重新索引数据,比较计数和样本查询,然后交换别名。除非你喜欢紧急配置更改,否则不要将应用程序直接指向products-v1。
一个谨慎的迁移如下所示:
PUT /products-v2
{
"mappings": {
"properties": {
"product_id": { "type": "keyword" },
"name": { "type": "text" },
"price": { "type": "scaled_float", "scaling_factor": 100 }
}
}
}
然后重新索引:
POST /_reindex?wait_for_completion=false
{
"source": { "index": "products-v1" },
"dest": { "index": "products-v2" }
}
使用wait_for_completion=false会返回一个任务ID,这样你就可以监控长时间的重新索引。完成后,比较文档计数并运行代表性搜索。只有在那之后才交换别名。
对于写入量大的索引,要考虑双写、暂停窗口或从真相来源重放。API命令很容易;一致性计划才是真正的工作。
安全性和权限
索引API不应该对每个应用程序用户都可用。搜索服务可能需要对别名的读取权限。数据摄取器可能需要对写入别名的创建、索引和写入权限。很少有身份应该拥有广泛的删除或管理权限。
这很重要,因为索引API功能强大。一个拥有manage权限的受损应用程序凭据可以更改副本设置、关闭索引或删除数据。将破坏性权限分开,并使生产环境中的删除需要操作员工作流程,而不是应用程序路径。
命名约定减少错误
使用编码了用途和生命周期的名称:products-v3、logs-web-2026.05.24、metrics-api-000123或与数据源匹配的数据流名称。避免使用模糊的名称,如newindex、test2或prod-final。在清理期间,模糊的名称使得很难知道哪些可以安全删除。
对于时间序列索引,使用一致的日期格式,避免混合本地时间和UTC假设。对于版本化的业务索引,保持别名稳定,让物理索引版本在其后更改。一个乏味的命名约定是一个操作安全特性。