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 コマンドを示しています。HTTP API を直接呼び出すのではなく、必ず CLI を使用してください。
プロセス
-
フィールドごとにアクセスパターンを収集します。 型を選ぶ前に、各フィールドの使用方法を列挙します。すべてのフィールドについて、以下を記録してください。
- 検索 — 全文検索、フレーズ検索、関連度スコアリングのどれを行いますか?
- フィルター — 完全一致の語句、語句の集合、プレフィックスのどれを使いますか?
- 集計 — terms、cardinality、histogram、stats のどれを使いますか?
- ソート — 結果セットを昇順/降順で並べ替えますか?
- 取得のみ —
_sourceには返されますが、クエリでは使用されませんか?
判断では、各フィールドを主なアクセスパターン(検索、完全一致、数値メトリック、日付、ブール値、構造化オブジェクト、取得のみ)のいずれかに分類します。アクセスパターンの情報が不足している場合は作業を進められません。推測せず、ユーザーに確認してください。接続を確認するために
GET /を呼び出します。既存のインデックスを確認する場合は、現在のマッピングに基づいて議論できるようGET /{index}/_mappingを呼び出します。 -
アクセスパターンに基づいてフィールド型を選びます。 各フィールドには、そのパターンを満たす最小限の型セットを割り当てます。マッピングを提案する前に、フィールド型の判断とマルチフィールドのパターンを読んでください。
主な判断基準:
パターン マッピング 全文検索のみ text(keyword サブフィールドなし)フィルター/集計/ソートのみ keyword(textではありません)全文検索 および ソートまたは集計 fields.keywordマルチフィールドを持つtext小数の価格またはメトリック double、float、またはscaled_float—textや整数ではありませんタイムスタンプ date真偽値のフラグ boolean多数の異なるキーを持つ自由形式のキー/値マップ flattened— 動的なobjectではありませんマルチフィールドのルール: フィールドを検索 かつ ソート/集計に使用する必要がある場合(例:商品名の
name)、keywordサブフィールドを持つtextとしてマッピングします。検索には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" } } } }settingsブロックとmappingsブロックを渡してPUT /productsで作成します。GET /products/_mappingで検証します。 -
マッピング爆発とストレージ肥大化を防ぐ。 大量データを扱うインデックスでは、型の誤りがコストを倍増させます。 マッピング爆発とストレージ肥大化を読み、以下のレビューチェックを適用してください:
- analyze されているが検索されないフィールド — フィルタと集計にのみ使用されるフィールド(
url、HTTPstatus_code、tags、ID)はtextではなくkeywordでなければなりません。textは容量を浪費します。textに対する集計には fielddata か.keywordサブフィールドが必要ですが、そのフィールドが検索されないのであれば、そのようなサブフィールドは 存在すべきではありません。 ignore_aboveのないmessage.keyword— 大きな全文本文に対する keyword サブフィールドは、生の文字列全体を 1 つのタームとしてインデックスします。このアンチパターンにフラグを立ててください。全文検索のみが必要な場合は サブフィールドを削除し、範囲を限定した完全一致サブフィールドが本当に必要な場合はignore_aboveを追加してください。- 動的な自由形式オブジェクト — 数千の異なるキーを持つユーザー提供のキー/値データに対して
"dynamic": trueを 指定したobjectは マッピング爆発 を引き起こします。flattened(または strict dynamic / 許可リスト戦略)を 推奨してください。 doc_values: false— ヒットで取得されるが、ソート・集計・フィルタのいずれも行われないフィールド (例: 表示専用のsession_id)では、keywordに"doc_values": falseを設定して大規模時のディスクを節約してください。scaled_float— 精度が限定的なメトリクス(例:response_time_ms)では、ストレージが支配的な場合、 通常のfloat/doubleよりも適切なscaling_factorを指定したscaled_floatを優先してください。
不明なフィールドが明示的な要件でない限り、ルートマッピングには
"dynamic": "strict"を優先してください。 - analyze されているが検索されないフィールド — フィルタと集計にのみ使用されるフィールド(
-
設計を適用する: 型が変わる場合は新しいインデックスを作成して reindex する。 Elasticsearch は既存フィールドの 型をその場で変更できません。レビューで誤った型(text→keyword、object→flattened、float→scaled_float、既存フィールドの doc_values 変更)が見つかった場合は、修正には新しいインデックスと reindex が必要であり、稼働中のインデックスに対する マッピング更新では不可能であることを明確に述べてください。
eventsのような既存の大量データインデックスを修正するワークフロー:- 修正したマッピングを設計する — 手順 2〜3 のすべての修正を反映した新しいインデックス名(例:
events-v2)で行います。 - 移行先を作成する —
PUT /events-v2と、完全に修正されたmappings(該当する場合はsettingsも)で行います。 - ドキュメントをコピーする —
POST /_reindexで行います。大きなインデックスの場合はwait_for_completion=falseを 使用し、タスクを追跡します。source:{ "index": "events" }、destination:{ "index": "events-v2" }。 - 検証する —
GET /events-v2/_count(source の件数と比較)および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" } } } }これらの型変更に対してその場でのマッピング修正を試みないでください — 拒否されるか、データが不整合な状態になります。 新規のインデックスでは、初回の取り込み前に 1 回
PUT /{index}を実行すれば、reindex を完全に回避できます。 - 修正したマッピングを設計する — 手順 2〜3 のすべての修正を反映した新しいインデックス名(例:
レビューチェックリスト
ユーザーがマッピング JSON と使用状況のメモを提供した場合、次のチェックリストを順に確認してください:
- 各フィールドの型を、記載されたアクセスパターンに合わせます(手順 2 を参照)。
- フィルタ/集計専用フィールドの
textにフラグを立てます。検索とソート/集計が 1 つの論理フィールドを共有している場合は、 マルチフィールドの欠落にフラグを立てます。 - 大きな analyze 対象テキストに対して
ignore_aboveのないmessage.keyword(または類似のもの)にフラグを立てます。 - カーディナリティの高い自由形式マップに対する動的な
objectにフラグを立て、flattenedを推奨します。 - 取得専用フィールドと数値のストレージ最適化(
doc_values: false、scaled_float)を提案します。 - 型の変更には新しいインデックスと
POST /_reindexが必要であることを述べ、修正したマッピングと reindex 計画を示します。
例
「ユーザーは商品名を検索し、さらにその名前で並べ替えや集計も行います」 — 1 つの論理フィールドに対して 2 つのアクセスパターンがあるため、keyword マルチフィールドを持つ
text フィールドを使用します。
{
"mappings": {
"properties": {
"product_name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }
}
}
}
「status フィールドはフィルタリングと集計にのみ使い、全文検索には使いません」 — text ではなく、keyword を使用します。
{ "mappings": { "properties": { "status": { "type": "keyword" } } } }
「キーが無制限の自由形式の labels オブジェクト」 — flattened を使ってマッピングの爆発を防ぎます。
{ "mappings": { "properties": { "labels": { "type": "flattened" } } } }
ガイドライン
- マッピングは最小限に — アクセスパターンで必要なものだけをマッピングします。サブフィールドや解析済み形式を追加するたびに、インデックスデータが増えます。
- アクセスパターンを推測しない — 型の選択を誤ると、規模が大きくなった際の修正コストが高くなります。
- 作成後に確認する — 必ず
GET /{index}/_mappingで確認します。再インデックス後はGET /{index}/_countを使います。 - スキルの適用範囲に注意 — インデックス間でドキュメントをコピーするには
POST /_reindexを使います(スライス、スロットリング、タスク追跡については 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>' |