LabHub

ブログ

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

한국어English日本語

TOC

1. Elasticsearchとは

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

1.1 なぜElasticsearchなのか

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

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

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)

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

2.3 Doc ValuesとFielddata

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

転置インデックス(検索用): TermDocument IDs
Doc Values(集約/ソート用): Document IDValues

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の主要(しゅよう)機能(きのう)


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"
  }
}

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

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プロジェクト

コメント

まだコメントはありません。

ログインするとコメントできます