关于 elasticsearch-index-design
根据字段访问模式设计和审查 Elasticsearch 索引映射的技能。它帮助数据与搜索从业者避免类型和存储问题,并在需要更改字段类型时规划新索引及重建索引。
主要功能
- 01按访问模式选择字段类型
- 02审查映射中的类型问题
- 03减少映射膨胀和存储占用
- 04设计显式映射和索引设置
- 05规划字段类型变更的重建索引
适用场景
- 01设计支持搜索和排序的新索引
- 02检查筛选和聚合字段的映射
- 03通过新索引和重建索引修正字段类型
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ elastic/ agent-skills --skill elasticsearch-index-design安装后在 Claude Code 中输入/elasticsearch-index-design确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/field-type-decisions.mdmapping-explosion.mdmulti-field-patterns.md详细介绍
Elasticsearch 索引设计
根据访问模式设计明确的索引映射,检查现有映射中的类型和存储问题;如果必须更改字段类型,则通过新建索引并重新索引来应用更正。
环境配置
此技能通过 elastic CLI 执行 Elasticsearch 操作。如果未安装
elastic CLI,请告知用户安装它的用途。不要猜测凭据、直接调用 HTTP API,也不要尝试其他变通方法。
此技能以 HTTP 简写形式引用操作(例如,GET /、GET /_cat/indices、GET /{index}/_mapping、
GET /{index}/_settings/index.mode、POST /_query)。本文档末尾的 操作 表格将每个简写映射到对应的 elastic CLI 命令——始终使用 CLI,而不要直接调用 HTTP API。
流程
-
收集各字段的访问模式。 在选择类型前,列出每个字段的用途。对每个字段记录:
- 搜索 — 全文匹配、短语匹配、相关性评分?
- 筛选 — 精确词项、词项集合、前缀?
- 聚合 — 词项、基数、直方图、统计信息?
- 排序 — 在结果集中升序或降序排列?
- 仅检索 — 在
_source中返回,但从不用于查询?
决策方式:将每个字段归入一种主要访问模式(搜索、精确匹配、数值指标、日期、布尔值、结构化对象或仅检索)。缺少访问模式数据时不得继续——应询问用户,而不是自行猜测。调用
GET /确认连接正常;检查现有索引时,调用GET /{index}/_mapping,以当前映射为依据展开讨论。 -
根据访问模式选择字段类型。 将每个字段映射为满足其模式所需的最精简类型集合。在提出映射前,阅读 字段类型选择 和 多字段模式。
关键判断:
模式 映射 仅全文搜索 text(不添加keyword子字段)仅筛选 / 聚合 / 排序 keyword(而非text)全文搜索 以及 排序或聚合 text,并带有fields.keyword多字段小数价格或指标 double、float或scaled_float——不能使用text或整数时间戳 date真/假标记 boolean包含许多不同键的自由格式键值映射 flattened——而非动态object多字段规则: 当某个字段必须可搜索 且 可排序或聚合时(例如产品
name),应将其映射为text,并添加keyword子字段——使用name搜索,使用name.keyword排序和聚合。对于这种组合模式,仅映射为text或仅映射为keyword都是错误的。显式映射规则: 对于新索引,始终使用
PUT /{index}显式定义映射。生产索引不要依赖动态映射——首个文档可能会锁定错误类型(字符串被映射为text,含义不明确的数字被映射为keyword)。索引设置: 在部署环境允许时(Self-Managed / Elastic Cloud Hosted),在同一
PUT /{index}请求中明确设置number_of_shards和number_of_replicas。在 Serverless 上省略分片数和副本数(由 Elastic 管理);仍须提供显式映射。说明所选值,或注明将使用默认值。 示例——针对搜索以及按 name 排序/聚合进行优化的products索引:{ "settings": { "number_of_shards": 1, "number_of_replicas": 1 }, "mappings": { "properties": { "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "price": { "type": "double" }, "created": { "type": "date" }, "in_stock": { "type": "boolean" } } } }创建时使用
PUT /products,并传入settings和mappings块。使用GET /products/_mapping验证。 -
防止映射膨胀和存储空间过度增长。 对于高流量索引,类型错误会导致成本成倍增加。阅读 映射膨胀和存储空间过度增长,并应用以下审查检查项:
- 已分析但不会搜索的字段——仅用于筛选和聚合的字段(
url、HTTPstatus_code、tags、ID)必须使用keyword,而不是text。text会浪费空间;对text进行聚合需要 fielddata,或者需要.keyword子字段;如果该字段不用于搜索,就不应有此子字段。 message.keyword未设置ignore_above——大型全文正文上的 keyword 子字段会将整个原始字符串作为一个词项索引。应指出这种反模式;如果只需要全文搜索,就移除该子字段;如果确实需要有长度限制的精确匹配子字段,则添加ignore_above。- 动态自由格式对象——对包含数千个不同键的用户提供键值数据使用
"dynamic": true的object,会导致映射膨胀。建议使用flattened(或严格动态模式/允许列表策略)。 doc_values: false——对于会在命中结果中返回、但从不用于排序、聚合或筛选的字段(例如仅用于显示的session_id),在keyword上设置"doc_values": false,以便在大规模场景下节省磁盘空间。scaled_float——对于精度有界的指标(例如response_time_ms),当存储成本占主导时,优先使用带有适当scaling_factor的scaled_float,而不是普通的float/double。
除非明确需要未知字段,否则优先在根映射上使用
"dynamic": "strict"。 - 已分析但不会搜索的字段——仅用于筛选和聚合的字段(
-
应用设计:类型变更时创建新索引并重新索引。 Elasticsearch 无法原地更改现有字段的类型。审查发现类型错误时(text→keyword、object→flattened、float→scaled_float、修改现有字段的 doc_values),应明确说明修复需要新索引和重新索引,而不是更新线上索引的映射。
修正现有高流量索引(例如
events)的工作流:- 设计修正后的映射,在新索引名称(例如
events-v2)下纳入步骤 2–3 中的所有修复。 - 使用
PUT /events-v2创建目标索引,并传入完整的修正后mappings(以及适用时的settings)。 - 使用
POST /_reindex复制文档——对于大型索引,使用wait_for_completion=false并跟踪任务。 源:{ "index": "events" },目标:{ "index": "events-v2" }。 - 使用
GET /events-v2/_count(与源索引的文档数比较)和GET /events-v2/_mapping(确认类型)进行验证。 - 验证后切换读写流量(交换索引别名或修改应用配置)。
events审查模式的修正示例片段:{ "mappings": { "properties": { "@timestamp": { "type": "date" }, "event_id": { "type": "keyword" }, "session_id": { "type": "keyword", "doc_values": false }, "url": { "type": "keyword" }, "status_code": { "type": "keyword" }, "response_time_ms": { "type": "scaled_float", "scaling_factor": 100 }, "tags": { "type": "keyword" }, "message": { "type": "text" }, "labels": { "type": "flattened" } } } }不要尝试原地修复这些类型变更——此类操作会被拒绝,或导致数据不一致。对于全新索引,在首次写入数据前执行一次
PUT /{index}即可完全避免重新索引。 - 设计修正后的映射,在新索引名称(例如
审查清单
用户提供映射 JSON 和用法说明时,按顺序逐项检查:
- 将每个字段的类型与其所述访问模式匹配(参见步骤 2)。
- 指出仅用于筛选/聚合的字段使用了
text;指出搜索与排序/聚合共用同一逻辑字段时缺少多字段。 - 指出大型已分析文本上的
message.keyword(或类似字段)未设置ignore_above。 - 指出高基数自由格式映射使用了动态
object;建议使用flattened。 - 提出仅用于返回字段和数值字段的存储优化建议(
doc_values: false、scaled_float)。 - 说明类型变更需要新索引和
POST /_reindex,然后展示修正后的映射和重新索引计划。
示例
“用户搜索产品名称,也会对其排序和进行聚合” — 一个逻辑字段,两种访问模式,因此使用带有 keyword 多字段的
text 字段:
{
"mappings": {
"properties": {
"product_name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }
}
}
}
“status 字段只用于筛选和聚合,从不进行全文搜索” — 使用 keyword,而非 text:
{ "mappings": { "properties": { "status": { "type": "keyword" } } } }
“键名不受限制的自由格式 labels 对象” — 使用 flattened 避免映射爆炸:
{ "mappings": { "properties": { "labels": { "type": "flattened" } } } }
指南
- 尽量精简映射 — 仅映射访问模式所需的字段;每个子字段和分析形式都会增加索引数据。
- 切勿猜测访问模式 — 类型选择错误后,在大规模数据中修正代价很高。
- 创建后验证 — 始终通过
GET /{index}/_mapping确认;重新索引后使用GET /{index}/_count。 - 跨技能边界 — 在索引之间复制文档时使用
POST /_reindex(切片、限流和任务跟踪请参阅重新索引技能)。将文件载入新索引属于批量摄取,而非索引设计。
参考资料
- 字段类型决策 — 访问模式到类型的对照表及常见错误
- 多字段模式 — text+keyword、
ignore_above、反模式 - 映射爆炸与存储膨胀 —
flattened、doc_values、动态对象
操作
| HTTP API(简写) | elastic CLI 命令 |
|---|---|
GET / | elastic es info |
GET /{index}/_mapping | elastic es indices get-mapping --index '<index>' |
PUT /{index} | elastic es indices create --index '<index>' --mappings '<json>' --settings '<json>' |
POST /_reindex | elastic es reindex --source '<json>' --dest '<json>' |
POST /_reindex?wait_for_completion=false | elastic es reindex --wait-for-completion false --source '<json>' --dest '<json>' |
GET /{index}/_count | elastic es count --index '<index>' |