データベース

Elasticsearchのマッピング設計|型選定とdynamicの制御、作り直しの手順

Elasticsearchのマッピング設計|型選定とdynamicの制御、作り直しの手順

索引を作ってドキュメントを投げれば、マッピングは勝手に付きます。検証データ千件なら、それで何も困りません。詰まるのは本番投入の直前です。日本語がtermクエリに当たらない、集計しようとしたら弾かれる、フィールドが千を超えて投入が止まる。いずれも索引を作った瞬間に決まっていた値が原因で、直すには索引ごと作り直すしかありません。9.5系(2026年8月時点)を前提に、着工前に決める値を順に見ていきます。

まとめ:マッピングを書く前に決める6つの値

マッピング設計とは、次の6点を決める作業です。ここが決まれば、残りは公式リファレンスの引き写しで足ります。決めないまま投入を始めると、データが増えた段階で作り直しになります。

  • 動的マッピングの扱い:dynamic を true・runtime・false・strict のどれで受けるか。業務検索はstrict、ログはruntimeかfalseが起点
  • 文字列項目の割り当て:項目ごとにtext・keyword・両持ちのどれにするか。既定は全ての文字列を両持ちにするので、放置すると索引が二重に膨らむ
  • 配列オブジェクトの持ち方:objectのままにするかnestedにするか。要素をまたいだ組み合わせ条件を引くかどうかで機械的に決まる
  • フィールド数の見込み:既定の上限は1索引あたり1,000。超える見込みがあるなら、上限を上げるのではなく受け方を先に決める
  • 索引テンプレートの有無:同じ設計の索引が今後も作られるなら、索引ごとに手で書かずテンプレートへ置く
  • 作り直しの方式:変更が出たときにエイリアス切替で入れ替えるか、停止時間を取って入れ直すか。最初の索引を作る時点で決めておく値

索引の物理設計は別の判断軸なので、Elasticsearchのチューニング|メモリ配分とシャード設計・遅いクエリの特定手順を参照してください。ここではフィールド定義だけを扱います。

変更できない前提から始める|追加は効いても型の差し替えは効かない

公式リファレンスは、既にマッピング済みのフィールドについて「ほとんどの場合、マッピングは変更できず、変更にはリインデックスが必要」と明記しています。型を後から直せるなら動かしながら考えれば済みますが、直せない以上、投入の前に決めるしかありません。

マッピングに追加できる操作と、索引ごと作り直すしかない操作の境目

公式が例外に挙げるのは、新しいフィールドの追加、既存フィールドへのmulti-field追加、特定データ型における一部パラメータの更新の3つ。この線引きを押さえておけば、変更要求が来たときに作り直しの要否を即断できます。

操作 既存の索引で可能か
フィールドを新しく追加する 可能
multi-fieldを後から足す 可能
ignore_aboveの値を変える 可能
dynamicの値を変える 可能
text型をkeyword型にする 不可・作り直し
索引時のanalyzerを替える 不可・作り直し
objectをnestedに替える 不可・作り直し

マッピングを直しても既に投入済みの文書は書き換わらないまま残る

もう一つ見落とされやすい性質があります。追加が通っても、既に投入済みの文書がその定義で索引し直されるわけではありません。追加したmulti-fieldに値が入るのは、追加後に投入または更新された文書だけです。既存分にも反映するなら_update_by_queryで全件を舐め直すことになり、件数が多ければ作り直しと変わらない負荷です。「追加は可能」を「無料で反映される」と読み替えないでください。

型の選び方|text型とkeyword型の分岐が設計の大半を決める

設計上の判断が要るのは、実質的に文字列だけです。同じ値に二通りの持ち方を選べるのが文字列型で、数値と日付は業務上の意味でおおよそ決まります。

解析するかしないか|全文検索はtext型、完全一致はkeyword型に寄せる

text型はanalyzerで値を語に分解してから転置索引へ入れます。keyword型は値をそのまま一つの語として入れる形。この差が、そのまま検索の当たり方の差になります。

公式がkeywordの用途例に挙げるのは、識別子、メールアドレス、ホスト名、ステータスコード、郵便番号、タグ。いずれも「部分一致で引きたくない」値で、ソート・集計・term系クエリの対象になります。逆に商品説明や記事本文のように語の一部で引きたい値はtext型です。termクエリが日本語に当たらない現象とその回避はElasticsearchのクエリDSL|queryとfilterの分岐、boolの組み立てと深いページングで扱っています。

text型とkeyword型を両持ちにする条件と、片方で足りる場面

動的マッピングの既定では、文字列は「text型と、その下に.keywordサブフィールドを持つ形」で作られます。検索も集計もできて一見便利ですが、索引を二重に持ち、フィールド数も1項目につき2つ消費するということでもあります。

両持ちが要るのは、同じ項目を全文検索とソートの両方で使う場合だけ。商品名やタイトルが該当します。識別子・ステータス・タグはkeyword単独、本文や説明文はtext単独で足ります。動的マッピングに任せきりの設計は、この判断を全項目で放棄したのと同じです。

さらに注意が要るのがignore_aboveです。動的マッピングが作る.keywordサブフィールドの既定値は256で、これを超える長さの値は索引されません。エラーは出ず、静かに落ちるだけ。長い文字列で集計をかけて「件数が合わない」と気づくのは、たいてい本番投入の後です。

数値型と日付型|識別子を数値のままで置いてよい場面の見分け方

注文番号や電話番号のように、桁で並ぶが計算はしない値があります。範囲検索とソートを本当に使うなら数値型、完全一致で引くだけならkeyword型が向きます。

日付には別の落とし穴があります。date_detectionは既定で有効ですが、判定に使うdynamic_date_formatsの既定はstrict_date_optional_timeともう一つの形式だけ。ここに当たらない日付文字列はdate型にならず、文字列として索引されます。範囲検索を書いた段階で気づく類の事故なので、日付項目はformatまで明示してください。なおnumeric_detectionは既定で無効で、引用符で囲んだ数値は文字列のまま入ります。

配列のオブジェクトはobject型で組が壊れる|nestedへ寄せる判断

公式は「Elasticsearchは内部オブジェクトという概念を持たない」と書いています。object型に配列のオブジェクトを入れると値が項目ごとに平坦化され、公式の例ではuser.firstが["alice","john"]、user.lastが["smith","white"]となって、どちらの姓がどちらの名と組だったかは失われます。結果として「aliceかつwhite」という存在しない組み合わせでも文書が当たってしまう。

nested型はこれを解決しますが、代償があります。配列の各要素を別の隠しLucene文書として索引するため、要素100件のオブジェクトは親を含めて101文書に。公式も「nested文書とnestedクエリは一般に高くつく」と明記し、上限も細かく引いています。1索引あたりのnestedマッピング数は100、親になれるnestedフィールドは50、1文書に含められるnestedオブジェクトの総数は10,000です。

同じ要素の中で姓と名が両方一致することを問う条件を引くならnested、単に値の集合として引くだけならobjectのまま。「念のためnested」は索引サイズとクエリ時間の両方を押し上げます。

dynamicの制御|4つの値のどれを既定に置くかで運用が割れる

設計したマッピングに載っていない項目が届いたとき、どう振る舞わせるか。ここを既定のまま放置した索引が、後でフィールド数の上限に当たります。

true・runtime・false・strictの4値と新しい項目が届いたときの動き

公式が定義する値は4つです。true(既定)は新しいフィールドをマッピングに追加。runtimeはruntime fieldとして追加し、索引はせず検索時に_sourceから読みます。falseは無視して索引もマッピング追加もしません(_sourceには残るので後から拾い直せます)。strictは例外を投げて文書そのものを拒否します。

選び方は、スキーマが仕様かどうかで決まります。項目が確定している業務検索の索引にはstrictを置きます。想定外の項目が届いた時点で投入が失敗し、送信側の実装ミスがその場で表面化するからです。逆にログのように送信元が勝手に項目を増やす索引は、拒否すると欠損になるためruntimeかfalseで受けます。

PUT orders
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "order_no":    { "type": "keyword" },
      "customer_id": { "type": "keyword" },
      "title":       { "type": "text",
                       "fields": {
                         "raw": { "type": "keyword", "ignore_above": 256 }
                       } },
      "amount":      { "type": "long" },
      "ordered_at":  { "type": "date", "format": "strict_date_optional_time" }
    }
  }
}

フィールド数の上限1000|引き上げる前に受け方の構造を疑う

index.mapping.total_fields.limitの既定は1,000です。数えられるのはフィールドとオブジェクトのマッピング、フィールドエイリアス、マップ済みのruntime fieldです。深さの上限depth.limitも20で引かれています。

上限に当たったとき、設定値を10,000に上げるのは対症療法です。フィールド定義はクラスタ状態として全ノードに配られるため、増えるほど管理役ノードの負荷とヒープを押します。上限に当たる索引の多くは、値であるべきものをキー名にしています。ホスト名やテナントIDをフィールド名へ埋め込む構造は、送信元が増えるたびに定義が増え続けるからです。この形ならflattened型へ寄せるか、キーと値の2項目を持つ配列へ組み替えるのが筋です。

それでも動的な項目を受けたいときの逃げ道がindex.mapping.total_fields.ignore_dynamic_beyond_limitです。既定はfalseですが、trueにすると上限超過分はマッピングに追加されず_ignoredフィールドへ回り、投入自体は成功します。投入を止めたくないログ系の索引で使う設定で、ヒープとクラスタ状態への影響はElasticsearchのチューニングと地続きです。

dynamic_templatesで型の当て方だけを先に宣言しておく

項目名が事前に分からなくても、型の当て方だけなら先に決められます。それがdynamic_templatesです。一致条件は、検出された型で判定するmatch_mapping_type、フィールド名のパターンで判定するmatchとunmatch、ドット区切りの完全パスで判定するpath_matchとpath_unmatch。match_patternを指定すれば、ワイルドカードではなくJava正規表現で書けます。

実務で効くのは、文字列を全てkeyword単独にするテンプレートです。既定の両持ちをやめるだけで、文字列項目あたりのフィールド数が半分になります。{{name}}と{{dynamic_type}}のプレースホルダで、フィールド名と検出型を差し込めます。

PUT logs-app
{
  "mappings": {
    "dynamic": true,
    "dynamic_templates": [
      {
        "ids_as_keyword": {
          "match": "*_id",
          "match_mapping_type": "long",
          "mapping": { "type": "keyword" }
        }
      },
      {
        "strings_as_keyword": {
          "match_mapping_type": "string",
          "mapping": { "type": "keyword", "ignore_above": 256 }
        }
      }
    ]
  }
}

注意が二つあります。公式は「テンプレートは順に処理され、最初に一致したものが勝つ」と明記しているため、狭い条件を上に置きます。上の例でids_as_keywordを先に置いているのはそのためです。もう一つ、match_mapping_type・match・path_matchのいずれも定義しないテンプレートは、どのフィールドにも一致しません。条件の書き忘れは、エラーではなく「何も起きない」形で現れます。

索引テンプレート|同じ設計を次に作られる索引へも自動で効かせる

設計を索引ごとに手で書くと、日次で索引が切り替わる構成では必ずずれます。索引テンプレートに置けば、索引パターンに当たる索引が作られた時点で設定とマッピングが当たる形に。共通部分をコンポーネントテンプレートへ切り出し、優先度で組み合わせるのが現行の書き方です。

テンプレートはこれから作られる索引にしか効きません。既存の索引には遡及せず、ロールオーバーで新しい索引へ切り替わったタイミングで初めて反映されます。この切り替わりの設計はElasticsearchのILM|5フェーズの設計とmin_ageの起点・データストリームとの使い分けで扱っています。用途が違う索引に同じテンプレートを当てないでください。

変更が要るとき|作り直しとエイリアス切替で止めずに入れ替える

型を変える要求は必ず来ます。textで作った項目を集計したい、analyzerを日本語向けに替えたい、といった話。これらはマッピングの更新では通らないので、新しい索引へ入れ直します。

作り直しの4段階|新索引を作り、写し、エイリアスを切り替える

手順は短いものです。まず新しいマッピングで別名の索引を作り、_reindexで写します。件数が多いならwait_for_completion=falseでタスク化し、進捗はタスクAPIで見る形に。写し終わったらエイリアスを付け替え、確認のうえで旧索引を消します。

POST _reindex?wait_for_completion=false
{
  "source": { "index": "orders_v1", "size": 2000 },
  "dest":   { "index": "orders_v2" }
}

POST _aliases
{
  "actions": [
    { "remove": { "index": "orders_v1", "alias": "orders" } },
    { "add":    { "index": "orders_v2", "alias": "orders" } }
  ]
}

アプリを最初からエイリアス経由で書けば切替の停止時間が消える

この手順が成立する条件は、アプリケーションが索引名ではなくエイリアスを見ていることです。_aliasesのactionsはremoveとaddを1リクエストにまとめれば原子的に切り替わり、参照先が一瞬で移ります。逆にアプリが索引名を直に持っていると、切替のたびにアプリ側のデプロイが要ります。

残るのは差分の追い付きです。写し始めてから切り替えるまでの間に入った更新は、新索引に入っていません。投入を止められるなら止めるのが確実で、止められないなら更新時刻を持たせて差分だけ追い写します。ここを設計しないと、切替後に「数十件だけ古い」状態が残ります。なお版を上げる過程で起きる索引の作り直しは目的も判断軸も違うため、Elasticsearchのバージョンアップと移行|8.19経由の必須経路とローリング手順・作り直しの判断を参照してください。

索引を作り直さずに済ませる二つの逃げ道と、その限界の見極め方

全ての変更で索引を作り直す必要はありません。逃げ道が二つあります。

一つはruntime fieldです。公式は「リインデックスなしで既存文書にフィールドを追加できる」「runtime fieldの追加は索引サイズを増やさない」と書いており、追加した直後から検索・集計・フィルタ・ソートに使えます。代償は検索時のスクリプト実行で、公式も「runtimeスクリプトの計算内容によっては検索性能に影響しうる」と注記。まずruntime fieldで出して要件を確かめ、引く頻度が上がった項目だけ索引フィールドへ昇格させる順序なら無駄が出ません。

もう一つはmulti-fieldの後付けです。既存のtextフィールドに.keywordを足す操作は通りますが、前述のとおり値が入るのは追加後に投入された文書だけ。既存分も揃えるなら_update_by_queryが要り、全件対象なら作り直しと手間は変わりません。判断の境目は、対象が既存文書を含むかどうかです。

_typeが消えた経緯|古い記事のサンプルがそのまま通らない理由

検索で見つかるマッピングのサンプルには、索引名のあとにタイプ名を挟む古い形式が今も多く残っています。これは9.5系(2026年8月時点)では通りません。経緯を知っておくと、記事がどの版のものかを見分けられます。

公式の記述をたどると、6.xで1索引1タイプに制限され_default_マッピングが非推奨になりました。6.8の時点でinclude_type_nameの既定はtrue。7.xでタイプ指定が非推奨となり、include_type_nameの既定がfalseへ変わり、_default_が削除されました。8.xでタイプ指定は非サポートとなり、include_type_name自体も削除されています。

代替として公式が示すのは、文書種別ごとに索引を分ける方式と、自前のtypeキーワードフィールドを持つ方式の二つ。公式は前者について、圧縮が効きスコアリングの精度も上がると案内しています。単一索引に複数種別を混ぜると項目が種別ごとに異なるためフィールド数が膨らみ、先ほどの上限にも当たりやすくなります。索引を分けるのが既定の選択です。

自分で設計してよい条件と、外部の設計工数へ寄せる判断の線引き

難しいのは構文ではなく、決めた型を後から変えられない状態で運用に載せる判断のほうです。

自前で設計を進めてよい三つの条件を、着工する前に確認しておく

次の3つが揃うなら、外部に頼まず設計して構いません。第一に、検索対象の項目が仕様として確定していてdynamicをstrictに倒せること。第二に、日本語の解析器と辞書を保守できる体制があること。ここはElasticsearchの日本語全文検索|kuromojiのanalyzer構成と辞書追加、N-gram併用の判断の範囲で、索引時analyzerの変更が作り直しを伴う点が効きます。第三に、作り直しの停止時間を確保できるか、エイリアス切替を組み込めること。製品そのものの前提はElasticsearchとは?転置インデックスとシャード設計・ライセンス系列で決める採用可否で確認してください。

見送る場面|項目がまだ増えているうちは本番索引を固めきらない

逆に、いま索引を固めないほうがよい場面もあります。項目が週単位で増えているフェーズです。設計を確定させても翌週には作り直しになるため、runtimeかfalseで受けて_sourceに貯め、引く頻度が定まった項目だけ索引フィールドへ昇格させてください。この段階で完成形のマッピングを書く作業は、ほぼ捨てることになります。

もう一つは、検索基盤が業務の中心にあり、作り直しの停止時間を業務側が許容できない場合です。エイリアス切替と差分追い付きを含めた移行設計は、索引の設計とは別の工程です。要件定義の段階から設計と移行手順をまとめて組み立てるなら、データ分析基盤構築・MLOps構築支援のような形で外部の設計工数を入れるほうが、作り直しを繰り返すより短く済みます。

よくある質問

マッピングは後から変更できますか?

フィールドの追加、multi-fieldの追加、一部パラメータの更新はできます。マッピング済みフィールドの型は変えられず、新しい索引を作ってリインデックスするしかありません。追加が通った場合も既存の文書は索引し直されないため、既存分への反映には_update_by_queryが要ります。

dynamic mappingはオフにすべきですか?

索引の用途で決まります。項目が仕様として確定している業務検索の索引はstrictに。想定外の項目を送る実装ミスが、その場で投入エラーとして表面化します。送信元が項目を増やすログ系でstrictにすると欠損になるため、runtimeかfalseで受けてください。

text型のフィールドで集計できないのはなぜですか?

text型はanalyzerで語に分解されて索引されるため、元の値がそのままの形で残っていないからです。集計やソートはkeyword型の側で行います。動的マッピング由来の索引なら.keywordサブフィールドがあるはずですが、既定のignore_aboveは256で、それを超える値は無言で集計から落ちます。

フィールド数の上限1000は引き上げてよいですか?

引き上げる前に構造を疑ってください。上限に当たる索引の多くは、ホスト名やテナントIDのように値であるべきものをフィールド名へ埋め込んでいます。この形ならflattened型か、キーと値の2項目を持つ配列へ組み替えるのが筋です。投入を止めたくない事情があるならindex.mapping.total_fields.ignore_dynamic_beyond_limitをtrueにすれば、超過分は_ignoredへ回って投入は通ります。

ネット上のサンプルにある_typeの指定はなぜ通らないのですか?

マッピングタイプが段階的に廃止されたためです。6.xで1索引1タイプに制限され、7.xでタイプ指定が非推奨かつinclude_type_nameの既定がfalseに、8.xでタイプ指定が非サポートとなりinclude_type_nameも削除されました。現行の9.5系(2026年8月時点)も同じです。複数の文書種別を扱うなら索引を分けてください。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.09 テックブログ IDCFクラウド(IDCフロンティア)不正アクセス・ランサムウェア:影響先・復旧・データは戻るか
  2. 2026.10.09 テックブログ ニッスイのサイバー攻撃で日水物流の入出荷停止|委託先クラウド障害に荷主が備える手順
  3. 2026.07.15 コラム LINEミニアプリとは?未認証と認証済みの違い・LIFFとの使い分け・審査と開発費用【2026年版】
  4. 2026.07.23 コラム クラウド販売管理システムとは?オンプレとの違い・料金相場と5年総額の比べ方【2026年】
  5. 2026.01.20 テックブログ PineDramaとは?TikTokのショートドラマアプリの日本配信・料金・安全性を解説

RELATED POSTS 関連記事

目次