Skip to content
Published on

Elasticsearch完全ガイド2025:検索エンジンからログ分析、ベクトル検索まで

Authors

TOC

1. Elasticsearchとは

Elasticsearchは、Apache Lucene基盤(きばん)の分散(ぶんさん)検索(けんさく)および分析(ぶんせき)エンジンです。2010年にShay Banonが最初(さいしょ)にリリースして以来(いらい)、全文検索(ぜんぶんけんさく)、ログ分析、メトリクス監視(かんし)、セキュリティ分析、そして最近(さいきん)ではベクトル検索(Vector Search)まで活用(かつよう)範囲(はんい)が拡大(かくだい)しています。

1.1 なぜElasticsearchなのか

従来(じゅうらい)のRDBMSでLIKE '%keyword%'クエリを実行(じっこう)すると、テーブル全体(ぜんたい)をフルスキャンする必要(ひつよう)があります。データが数億件(すうおくけん)になると応答(おうとう)時間(じかん)が数十秒(すうじゅうびょう)に達(たっ)する可能性(かのうせい)があります。Elasticsearchは転置(てんち)インデックス(Inverted Index)構造(こうぞう)を使用(しよう)してミリ秒(びょう)単位(たんい)の検索応答を提供(ていきょう)します。

主要(しゅよう)な特徴(とくちょう):

  • 分散アーキテクチャ: 水平(すいへい)スケーリング(Scale-out)が可能(かのう)で数十TBのデータ処理(しょり)
  • 準(じゅん)リアルタイム検索: 文書(ぶんしょ)インデックス後(ご)約(やく)1秒(びょう)以内(いない)に検索可能(Near Real-Time)
  • スキーマレス: JSONドキュメントをそのままインデックス可能、動的(どうてき)マッピング対応(たいおう)
  • RESTful API: すべての操作(そうさ)をHTTP/JSONで実行
  • 豊富(ほうふ)なエコシステム: Kibana、Logstash、Beats、APMとの統合(とうごう)

1.2 Elasticsearch vs RDBMS比較

項目(こうもく)RDBMSElasticsearch
データ単位RowDocument (JSON)
コレクションTableIndex
カラムColumnField
スキーマ固定(こてい)スキーマ動的マッピング可能
検索方式(ほうしき)B-Treeインデックス転置インデックス
拡張(かくちょう)方式Scale-up中心Scale-out (Sharding)
トランザクションACID対応非対応
主な用途(ようと)OLTP検索、分析、ロギング

1.3 バージョン履歴(りれき)

ES 1.x (2014) - 初期安定化
ES 2.x (2015) - Pipeline Aggregation導入
ES 5.x (2016) - Lucene 6、Painlessスクリプティング
ES 6.x (2017) - インデックスごとに単一タイプ
ES 7.x (2019) - タイプ廃止、アダプティブレプリカ選択
ES 8.x (2022) - セキュリティデフォルト有効化、kNNベクトル検索、NLP統合

2. 転置インデックスの仕組(しく)み

Elasticsearchの検索速度(そくど)の秘密(ひみつ)は転置インデックスにあります。一般的(いっぱんてき)なデータベースが文書(ぶんしょ)から単語(たんご)を探(さが)す(Forward Index)のに対(たい)し、転置インデックスは単語から文書を探します。

2.1 転置インデックス構造

3つの文書があると仮定(かてい)します:

Doc 1: "The quick brown fox"
Doc 2: "The quick brown dog"
Doc 3: "The lazy brown fox"

転置インデックスは以下(いか)のように構成(こうせい)されます:

Term      | Document IDs
----------|-------------
the       | [1, 2, 3]
quick     | [1, 2]
brown     | [1, 2, 3]
fox       | [1, 3]
dog       | [2]
lazy      | [3]

「fox」を検索すると、転置インデックスからすぐにDoc 1、Doc 3を見(み)つけることができます。文書数(ぶんしょすう)がどれだけ多(おお)くても、単語(たんご)の検索(けんさく)はO(1)に近(ちか)いです。

2.2 Luceneセグメント構造

Elasticsearch内部(ないぶ)のLuceneはデータをセグメント(Segment)単位(たんい)で保存(ほぞん)します:

Index
  └── Shard (Lucene Index)
        ├── Segment 0 (immutable)
        │     ├── Inverted Index
        │     ├── Stored Fields
        │     ├── Doc Values
        │     └── Term Vectors
        ├── Segment 1 (immutable)
        ├── Segment 2 (immutable)
        └── Commit Point (segments_N)

重要(じゅうよう)なポイント:

  • セグメントは一度(いちど)作成(さくせい)されると変更(へんこう)不可(ふか)(Immutable)
  • 文書削除(さくじょ)時は実際(じっさい)には削除せず.delファイルにマーク
  • バックグラウンドでセグメントマージ(Merge)が発生(はっせい)
  • Refresh(デフォルト1秒)ごとに新しいセグメントが作成(さくせい)され検索可能になる

2.3 Doc ValuesとFielddata

転置インデックスはテキスト検索に最適化(さいてきか)されていますが、ソートや集約(しゅうやく)には適(てき)していません:

転置インデックス(検索用): TermDocument IDs
Doc Values(集約/ソート用): Document IDValues
  • Doc Values: keywordnumericdateipgeo_pointタイプで自動(じどう)有効(ゆうこう)化。ディスクベース。
  • Fielddata: textタイプのソート/集約時に使用。ヒープメモリ使用のため注意(ちゅうい)が必要。

3. マッピングとアナライザ

3.1 マッピング定義(ていぎ)

マッピングはインデックスのスキーマを定義します。各フィールドのタイプと分析方法(ほうほう)を指定(してい)します。

PUT /products
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "standard",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "price": {
        "type": "float"
      },
      "category": {
        "type": "keyword"
      },
      "description": {
        "type": "text"
      },
      "created_at": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
      },
      "location": {
        "type": "geo_point"
      },
      "tags": {
        "type": "keyword"
      },
      "reviews": {
        "type": "nested",
        "properties": {
          "author": { "type": "keyword" },
          "rating": { "type": "integer" },
          "comment": { "type": "text" }
        }
      }
    }
  }
}

3.2 主要(しゅよう)フィールドタイプ

タイプ説明(せつめい)転置インデックスDoc Values
text全文検索用(アナライザ適用)OX (Fielddata)
keyword完全一致(いっち)、ソート、集約OO
long/integer/float数値(すうち)O (BKD Tree)O
date日付(ひづけ)/時刻(じこく)OO
booleantrue/falseOO
geo_point緯度(いど)/経度(けいど)OO
nestedネスト対象(独立(どくりつ)文書)OO
dense_vectorベクトル(kNN検索)XX(別途(べっと)格納(かくのう))

3.3 アナライザパイプライン

アナライザは3つのステージで構成(こうせい)されます:

テキスト入力
Character Filter(文字フィルタ)
- html_strip: HTMLタグ除去
- mapping: 文字置換
- pattern_replace: 正規表現置換
Tokenizer(トークナイザ)
- standard: Unicode単語境界基盤
- whitespace: 空白基準分割
- ngram: N-gramトークン生成
- edge_ngram: プレフィックスベーストークン
- kuromoji_tokenizer: 日本語形態素解析
Token Filter(トークンフィルタ)
- lowercase: 小文字変換
- stop: ストップワード除去
- synonym: 同義語処理
- stemmer: ステミング
- kuromoji_part_of_speech: 日本語品詞フィルタ
トークンストリーム(Term)

3.4 日本語(にほんご)アナライザ設定(せってい)(Kuromoji)

PUT /japanese_index
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "kuromoji_custom": {
          "type": "kuromoji_tokenizer",
          "mode": "search",
          "discard_punctuation": true,
          "user_dictionary_rules": [
            "エラスティックサーチ,エラスティックサーチ,エラスティックサーチ,カスタム名詞"
          ]
        }
      },
      "filter": {
        "kuromoji_pos_filter": {
          "type": "kuromoji_part_of_speech",
          "stoptags": [
            "助詞-格助詞",
            "助詞-係助詞",
            "助詞-終助詞"
          ]
        }
      },
      "analyzer": {
        "japanese_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_custom",
          "filter": [
            "kuromoji_baseform",
            "kuromoji_pos_filter",
            "lowercase",
            "cjk_width"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "japanese_analyzer"
      }
    }
  }
}

3.5 Analyze APIで分析結果(けっか)を確認(かくにん)

POST /japanese_index/_analyze
{
  "analyzer": "japanese_analyzer",
  "text": "Elasticsearchは強力な検索エンジンです"
}

// 結果
{
  "tokens": [
    { "token": "elasticsearch", "position": 0 },
    { "token": "強力", "position": 2 },
    { "token": "検索", "position": 4 },
    { "token": "エンジン", "position": 5 }
  ]
}

4. Query DSL完全(かんぜん)攻略(こうりゃく)

ElasticsearchのQuery DSLはJSON基盤の強力(きょうりょく)なクエリ言語(げんご)です。大きくQuery Context(関連度(かんれんど)スコア計算(けいさん))とFilter Context(Yes/No判定(はんてい)、キャッシング)に分(わ)かれます。

4.1 Match Query(全文検索)

// 基本match - アナライザでトークン化後に検索
GET /products/_search
{
  "query": {
    "match": {
      "description": "強力な検索エンジン"
    }
  }
}

// match_phrase - 単語の順序まで一致
GET /products/_search
{
  "query": {
    "match_phrase": {
      "description": {
        "query": "検索エンジン",
        "slop": 1
      }
    }
  }
}

// multi_match - 複数フィールドで検索
GET /products/_search
{
  "query": {
    "multi_match": {
      "query": "Elasticsearchガイド",
      "fields": ["title^3", "description", "tags^2"],
      "type": "best_fields"
    }
  }
}

4.2 Term Query(完全一致)

// term - keywordフィールドの完全一致
GET /products/_search
{
  "query": {
    "term": {
      "category": "electronics"
    }
  }
}

// terms - 複数値のいずれかに一致
GET /products/_search
{
  "query": {
    "terms": {
      "status": ["published", "pending"]
    }
  }
}

// range - 範囲検索
GET /products/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 100,
        "lte": 500
      }
    }
  }
}

// exists - フィールド存在確認
GET /products/_search
{
  "query": {
    "exists": {
      "field": "discount"
    }
  }
}

4.3 Bool Query(複合(ふくごう)クエリ)

GET /products/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "description": "検索エンジン" } }
      ],
      "must_not": [
        { "term": { "status": "deleted" } }
      ],
      "should": [
        { "term": { "featured": true } },
        { "range": { "rating": { "gte": 4.5 } } }
      ],
      "filter": [
        { "term": { "category": "software" } },
        { "range": { "price": { "lte": 1000 } } }
      ],
      "minimum_should_match": 1
    }
  }
}

Bool Queryの各(かく)節(せつ)(Clause):

スコア反映(はんえい)キャッシュ用途(ようと)
mustOX必須(ひっす)一致+スコア計算
must_notXO必須不一致
shouldOX一致で加点(かてん)
filterXO必須一致(スコア無関係(むかんけい))

4.4 Nested Query

GET /products/_search
{
  "query": {
    "nested": {
      "path": "reviews",
      "query": {
        "bool": {
          "must": [
            { "term": { "reviews.author": "john" } },
            { "range": { "reviews.rating": { "gte": 4 } } }
          ]
        }
      },
      "inner_hits": {
        "size": 3,
        "highlight": {
          "fields": {
            "reviews.comment": {}
          }
        }
      }
    }
  }
}

4.5 Function Score Query

GET /products/_search
{
  "query": {
    "function_score": {
      "query": { "match": { "title": "elasticsearch" } },
      "functions": [
        {
          "field_value_factor": {
            "field": "popularity",
            "modifier": "log1p",
            "factor": 2
          }
        },
        {
          "gauss": {
            "created_at": {
              "origin": "now",
              "scale": "30d",
              "decay": 0.5
            }
          }
        },
        {
          "filter": { "term": { "featured": true } },
          "weight": 5
        }
      ],
      "score_mode": "sum",
      "boost_mode": "multiply"
    }
  }
}

5. 集約(しゅうやく)(Aggregation)完全攻略

Elasticsearchの集約はSQLのGROUP BYに相当(そうとう)しますが、はるかに強力です。バケット集約、メトリック集約、パイプライン集約に分類(ぶんるい)されます。

5.1 Bucket Aggregation

// terms集約 - カテゴリ別文書数
GET /products/_search
{
  "size": 0,
  "aggs": {
    "by_category": {
      "terms": {
        "field": "category",
        "size": 20,
        "order": { "_count": "desc" }
      }
    }
  }
}

// date_histogram - 時間帯別集約
GET /logs/_search
{
  "size": 0,
  "aggs": {
    "logs_per_hour": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "1h",
        "time_zone": "Asia/Tokyo",
        "min_doc_count": 0
      }
    }
  }
}

// ネスト集約 - カテゴリ別平均価格
GET /products/_search
{
  "size": 0,
  "aggs": {
    "by_category": {
      "terms": { "field": "category" },
      "aggs": {
        "avg_price": {
          "avg": { "field": "price" }
        },
        "price_stats": {
          "stats": { "field": "price" }
        }
      }
    }
  }
}

5.2 Metric Aggregation

GET /products/_search
{
  "size": 0,
  "aggs": {
    "avg_price": { "avg": { "field": "price" } },
    "max_price": { "max": { "field": "price" } },
    "min_price": { "min": { "field": "price" } },
    "total_sales": { "sum": { "field": "sales_count" } },
    "unique_brands": { "cardinality": { "field": "brand" } },
    "price_percentiles": {
      "percentiles": {
        "field": "price",
        "percents": [25, 50, 75, 90, 99]
      }
    }
  }
}

5.3 Pipeline Aggregation

GET /sales/_search
{
  "size": 0,
  "aggs": {
    "monthly_sales": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "month"
      },
      "aggs": {
        "total_revenue": {
          "sum": { "field": "revenue" }
        }
      }
    },
    "avg_monthly_revenue": {
      "avg_bucket": {
        "buckets_path": "monthly_sales>total_revenue"
      }
    },
    "max_monthly_revenue": {
      "max_bucket": {
        "buckets_path": "monthly_sales>total_revenue"
      }
    }
  }
}

6. ELKスタック(Logstash, Kibana, Beats)

6.1 ELKスタックアーキテクチャ

データソース              収集               処理/変換            格納              可視化
┌──────────┐          ┌──────────┐      ┌──────────┐      ┌──────────┐      ┌──────────┐
App Log │──────────│ Filebeat │──────│ Logstash │──────│  Elastic │──────│  KibanaServer  │          │ Metricbt │      │ Pipeline │      │  search  │      │Dashboard │
Docker  │          │ Heartbt (Filter) │      │ Cluster  │      │ Lens/MapK8s     │          │ Packetbt │      │          │      │          │      │ Alerting└──────────┘          └──────────┘      └──────────┘      └──────────┘      └──────────┘

6.2 Logstashパイプライン

# /etc/logstash/conf.d/main.conf
input {
  beats {
    port => 5044
  }
  kafka {
    bootstrap_servers => "kafka:9092"
    topics => ["app-logs"]
    codec => json
  }
}

filter {
  # Grokパターンで非構造化ログをパース
  grok {
    match => {
      "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:msg}"
    }
  }

  # 日付パース
  date {
    match => ["timestamp", "ISO8601"]
    target => "@timestamp"
  }

  # GeoIP変換
  geoip {
    source => "client_ip"
    target => "geo"
  }

  # 条件付き処理
  if [level] == "ERROR" {
    mutate {
      add_tag => ["alert"]
      add_field => { "severity" => "high" }
    }
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "logs-%{+YYYY.MM.dd}"
    user => "elastic"
    password => "changeme"
  }
}

6.3 Filebeat設定

# /etc/filebeat/filebeat.yml
filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/log/app/*.log
    multiline:
      pattern: '^\d{4}-\d{2}-\d{2}'
      negate: true
      match: after

  - type: container
    paths:
      - /var/lib/docker/containers/*/*.log
    processors:
      - add_docker_metadata: ~

output.logstash:
  hosts: ["logstash:5044"]

6.4 Kibanaの主要(しゅよう)機能(きのう)

  • Discover: ログ検索、フィルタリング、時間(じかん)帯(たい)別(べつ)分布(ぶんぷ)
  • Dashboard: 複数(ふくすう)のビジュアライゼーションをまとめてダッシュボード構成(こうせい)
  • Lens: ドラッグ&ドロップ可視化(かしか)ビルダー
  • Maps: 地理(ちり)データ可視化
  • Alerting: 条件(じょうけん)ベースのアラート(Slack、Email、PagerDuty)
  • APM: アプリケーションパフォーマンスモニタリング
  • Security: SIEM機能、セキュリティイベント分析
  • Dev Tools: コンソールから直接(ちょくせつ)API呼(よ)び出(だ)し

7. ベクトル検索とkNN

Elasticsearch 8.xからネイティブに内蔵(ないぞう)されたベクトル検索は、意味(いみ)ベースの検索(Semantic Search)を可能にします。

7.1 ベクトル検索とは

従来のキーワード検索は正確(せいかく)な単語一致(いっち)に依存(いぞん)します。「自動車(じどうしゃ)」を検索しても「車両(しゃりょう)」や「vehicle」は見(み)つかりません。ベクトル検索はテキストを高次元(こうじげん)ベクトルに変換(へんかん)して意味的(いみてき)な類似度(るいじど)を計算(けいさん)します。

"自動車"[0.12, -0.34, 0.56, ..., 0.89]  (768次元)
"車両"[0.13, -0.32, 0.55, ..., 0.88]  (類似ベクトル)
"果物"[-0.45, 0.67, -0.12, ..., 0.23] (異なるベクトル)

7.2 kNN検索インデックス設定

PUT /semantic-search
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "content": { "type": "text" },
      "content_vector": {
        "type": "dense_vector",
        "dims": 768,
        "index": true,
        "similarity": "cosine",
        "index_options": {
          "type": "hnsw",
          "m": 16,
          "ef_construction": 200
        }
      }
    }
  }
}

7.3 kNN検索の実行(じっこう)

// 純粋kNN検索
GET /semantic-search/_search
{
  "knn": {
    "field": "content_vector",
    "query_vector": [0.12, -0.34, 0.56],
    "k": 10,
    "num_candidates": 100
  }
}

// ハイブリッド検索(キーワード + kNN)
GET /semantic-search/_search
{
  "query": {
    "match": {
      "content": "自動車 おすすめ"
    }
  },
  "knn": {
    "field": "content_vector",
    "query_vector": [0.12, -0.34, 0.56],
    "k": 10,
    "num_candidates": 100,
    "boost": 0.5
  },
  "size": 10
}

7.4 HNSWアルゴリズム

HNSW(Hierarchical Navigable Small World)はkNN検索に使用(しよう)される近似(きんじ)最近傍(さいきんぼう)(ANN)アルゴリズムです:

Layer 2 (sparse):  A ──── B
Layer 1 (medium):  A ── C ── B ── D
                   │    │    │    │
Layer 0 (dense):   A-E-C-F-B-G-D-H
パラメータ説明デフォルトトレードオフ
m各ノードの接続(せつぞく)数16高いほど正確だがメモリ増加
ef_constructionインデックス構築(こうちく)時の探索(たんさく)範囲200高いほど正確だがインデックス遅延
ef検索時の探索範囲100高いほど正確だが検索遅延

8. クラスタ運用(うんよう)と管理(かんり)

8.1 クラスタアーキテクチャ

┌─────────────────────────────────────────────────┐
Elasticsearch Cluster│                                                   │
│  ┌─────────────┐  ┌─────────────┐  ┌────────────┐│
│  │ Master Node │  │ Master Node │  │Master Node ││
  (Elected) (Eligible)(Eligible)  ││
│  └─────────────┘  └─────────────┘  └────────────┘│
│                                                   │
│  ┌─────────────┐  ┌─────────────┐  ┌────────────┐│
│  │  Data Node  │  │  Data Node  │  │ Data Node  ││
 (Hot Tier) (Hot Tier)(Warm Tier) ││
│  │  SSD 1TB    │  │  SSD 1TB    │  │ HDD 4TB    ││
│  └─────────────┘  └─────────────┘  └────────────┘│
│                                                   │
│  ┌─────────────┐  ┌─────────────┐                │
│  │ Ingest Node │  │ Coord Node  │                │
 (Pipeline) (Routing)   │                │
│  └─────────────┘  └─────────────┘                │
└─────────────────────────────────────────────────┘

8.2 シャード戦略(せんりゃく)

PUT /logs-2025.03
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "routing.allocation.require.data": "hot"
  }
}

シャードサイジングガイドライン:

  • シャード1つあたり10-50GB推奨(すいしょう)
  • ノードあたりのシャード数:ヒープ1GBあたり20個以下
  • 時系列(じけいれつ)データは日付ベースのインデックスを使用

8.3 Index Lifecycle Management (ILM)

PUT /_ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "50gb",
            "max_age": "1d"
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 },
          "allocate": { "require": { "data": "warm" } },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": { "require": { "data": "cold" } },
          "freeze": {}
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": { "delete": {} }
      }
    }
  }
}

8.4 クラスタ監視(かんし)API

# クラスタ状態
GET /_cluster/health

# ノード統計
GET /_nodes/stats

# インデックス状態
GET /_cat/indices?v&s=store.size:desc

# シャード割り当て状態
GET /_cat/shards?v&s=store:desc

# 割り当て失敗原因
GET /_cluster/allocation/explain

9. パフォーマンス最適化(さいてきか)

9.1 インデックスパフォーマンス

// Bulk API(個別リクエストの10倍以上高速)
POST /_bulk
{"index": {"_index": "products", "_id": "1"}}
{"name": "Product 1", "price": 100}
{"index": {"_index": "products", "_id": "2"}}
{"name": "Product 2", "price": 200}

インデックス最適化チェックリスト:

項目設定効果(こうか)
Bulkサイズリクエストあたり5-15MBネットワークオーバーヘッド削減
Refresh Interval"30s"または"-1"セグメント生成頻度(ひんど)削減
レプリカ数初期ロード時0レプリケーションオーバーヘッド除去(じょきょ)
Translog"async"フラッシュディスクI/O削減
ID生成自動生成ID使用ID重複(じゅうふく)チェック省略(しょうりゃく)

9.2 検索パフォーマンス

// 1. Filter Context活用(キャッシュされる)
GET /products/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "category": "electronics" } },
        { "range": { "price": { "gte": 100, "lte": 500 } } }
      ],
      "must": [
        { "match": { "description": "wireless" } }
      ]
    }
  }
}

// 2. Source Filtering(必要なフィールドのみ)
GET /products/_search
{
  "_source": ["name", "price", "category"],
  "query": { "match_all": {} }
}

// 3. Search After(Deep Paginationの代替)
GET /products/_search
{
  "size": 20,
  "sort": [
    { "created_at": "desc" },
    { "_id": "asc" }
  ],
  "search_after": ["2025-03-01T00:00:00", "abc123"]
}

9.3 キャッシュ戦略

Elasticsearchキャッシュ階層:

1. Node Query Cache(Filter Cache)
   - filter contextの結果をキャッシュ
   - ノードレベル、ヒープの10%(デフォルト)
   - LRU方式除去

2. Shard Request Cache
   - 集約結果をキャッシュ
   - シャードレベル、ヒープの1%(デフォルト)
   - インデックスrefresh時に無効化

3. OS Page Cache
   - Luceneセグメントファイルのキャッシュ
   - ヒープ外メモリを活用
   - 最も重要なキャッシュ!

10. 実践(じっせん)運用パターン

10.1 Index TemplateとComponent Template

// Component Template(再利用可能なブロック)
PUT /_component_template/base-settings
{
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs-policy"
    }
  }
}

PUT /_component_template/log-mappings
{
  "template": {
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" },
        "service": { "type": "keyword" },
        "trace_id": { "type": "keyword" }
      }
    }
  }
}

// Index Template
PUT /_index_template/logs
{
  "index_patterns": ["logs-*"],
  "composed_of": ["base-settings", "log-mappings"],
  "priority": 200
}

10.2 AliasとReindex

// Alias設定(無停止インデックス切り替え)
POST /_aliases
{
  "actions": [
    { "remove": { "index": "products-v1", "alias": "products" } },
    { "add": { "index": "products-v2", "alias": "products" } }
  ]
}

// Reindex(インデックスマイグレーション)
POST /_reindex
{
  "source": {
    "index": "old-index",
    "query": {
      "range": {
        "@timestamp": { "gte": "2025-01-01" }
      }
    }
  },
  "dest": {
    "index": "new-index",
    "pipeline": "enrichment-pipeline"
  }
}

10.3 SnapshotとRestore

// リポジトリ登録(S3)
PUT /_snapshot/s3-backup
{
  "type": "s3",
  "settings": {
    "bucket": "my-es-backups",
    "region": "ap-northeast-1",
    "base_path": "elasticsearch"
  }
}

// スナップショット作成
PUT /_snapshot/s3-backup/snapshot-2025-03-24
{
  "indices": "logs-*,products",
  "ignore_unavailable": true,
  "include_global_state": false
}

// 復元
POST /_snapshot/s3-backup/snapshot-2025-03-24/_restore
{
  "indices": "products",
  "rename_pattern": "(.+)",
  "rename_replacement": "restored-$1"
}

11. 面接対策(めんせつたいさく)クイズ

Q1. Elasticsearchで文書をインデックスした後すぐに検索できない理由は?

ElasticsearchはNear Real-Time(NRT)検索エンジンです。文書がインデックスされると、まずメモリバッファ(In-Memory Buffer)とトランザクションログ(Translog)に記録(きろく)されます。検索可能にするにはRefresh処理(しょり)を通(つう)じてメモリバッファの内容(ないよう)が新しいLuceneセグメントとして生成(せいせい)される必要があります。

デフォルトのRefresh間隔(かんかく)は1秒で、これが「Near Real-Time」と呼(よ)ばれる理由(りゆう)です。

  • index.refresh_interval設定で調整(ちょうせい)可能
  • 即時(そくじ)検索が必要な場合はPOST /index/_refresh API呼び出し
  • 大量インデックス時は-1に設定して無効化後、完了後に手動(しゅどう)refresh
Q2. textタイプとkeywordタイプの違(ちが)いは?

textタイプ:

  • アナライザでトークン化される
  • 転置インデックスに個別(こべつ)トークンで格納
  • 全文検索(Full-Text Search)に使用(match query)
  • Doc Values非対応(ソート/集約時はFielddata使用、メモリ注意)

keywordタイプ:

  • 分析(ぶんせき)なしで原文(げんぶん)のまま格納
  • 完全一致検索に使用(term query)
  • ソート、集約、フィルタリングに最適化
  • Doc Values対応(ディスクベース)

実務(じつむ)のヒント: nameのようなフィールドはMulti-fieldで両方(りょうほう)のタイプを設定するのが一般的(いっぱんてき)です。

Q3. Bool Queryのmustとfilterの違いは?

どちらも「必ず一致(いっち)しなければならない」条件ですが、重要(じゅうよう)な違いがあります:

must:

  • 関連度スコア(_score)を計算
  • キャッシュされない
  • 「どの程度(ていど)一致するか」が重要な場合に使用

filter:

  • スコアを計算しない(0点)
  • 結果がキャッシュされる(Node Query Cache)
  • 「一致するか/しないか」だけが重要な場合に使用

最適化の原則(げんそく): スコアが不要な条件はすべてfilterに移動(いどう)してください。

Q4. Primary ShardとReplica Shardの役割(やくわり)は?

Primary Shard:

  • インデックスデータの原本(げんぽん)を格納
  • インデックス作成後に数(かず)を変更不可(shrink/split除外(じょがい))
  • すべてのWrite要求はまずPrimary Shardで処理
  • データ分散の単位

Replica Shard:

  • Primary Shardのコピー
  • 動的に数を変更可能
  • 2つの役割:
    1. 高可用性(こうかようせい): Primary Shard障害(しょうがい)時にReplicaが昇格(しょうかく)
    2. 検索性能(せいのう): 検索リクエストを分散処理(Read負荷(ふか)分散)
  • Primaryと同じノードには配置(はいち)されない
Q5. ElasticsearchでDeep Paginationが危険な理由と代替案(だいたいあん)は?

Deep Paginationの問題: from: 10000, size: 10のリクエスト時、各シャードで10,010件の文書をソートしてCoordinating Nodeに送信(そうしん)する必要があります。3つのシャードなら30,030件をメモリでソートしなければなりません。ページが深(ふか)くなるほどリソース消費(しょうひ)が指数関数的(しすうかんすうてき)に増加します。

代替案:

  1. Search After: 前のページの最後のソート値を基準(きじゅん)に次のページを取得。リアルタイムカーソルベース。
  2. Point in Time (PIT): Scrollの代替。search_afterと組み合わせて一貫(いっかん)したビューを提供。
// PIT + Search After例
POST /products/_pit?keep_alive=5m

GET /_search
{
  "pit": { "id": "PIT_ID", "keep_alive": "5m" },
  "size": 20,
  "sort": [{ "created_at": "desc" }, { "_shard_doc": "asc" }],
  "search_after": [1679616000000, 42]
}

12. 参考(さんこう)資料(しりょう)

  1. Elasticsearch公式ドキュメント
  2. Elasticsearch: The Definitive Guide
  3. Elastic公式ブログ
  4. Lucene内部構造
  5. ELKスタックチュートリアル
  6. Elasticsearchベクトル検索ガイド
  7. HNSWアルゴリズム論文
  8. Kuromoji日本語アナライザ
  9. Elasticsearchパフォーマンスチューニングガイド
  10. Index Lifecycle Management
  11. Elastic ELSERモデル
  12. Elasticsearchクラスタ運用ガイド
  13. OpenSearchプロジェクト