Elasticsearch チートシート:必須コマンドとコツ

検索、インデックス作成、および分析のための Elasticsearch コマンド

目次

Elasticsearch は、Apache Lucene を基盤に構築された強力な分散型検索および分析エンジンです。 この包括的なチートシートでは、Elasticsearch クラスターを操作するための重要なコマンド、ベストプラクティス、およびクイックリファレンスを取り上げています。

elasticsearch

注意: このガイドのほとんどの例では、HTTP リクエストに cURL を使用しています。cURL が初めての方、または高度なオプションのクイックリファレンスが必要な場合は、詳細なコマンドライン HTTP リクエスト技術について記載している cURL チートシート を参照してください。

クラスター管理

クラスターヘルスチェック

このセクションのコマンドはすべて、cURL を使用して Elasticsearch の REST API と通信します。必要に応じて、追加のヘッダーや認証情報、その他のオプションでこれらのリクエストをカスタマイズできます。

# 基本的なヘルスチェック
curl -X GET "localhost:9200/_cluster/health?pretty"

# シャード情報を含む詳細なクラスターヘルス
curl -X GET "localhost:9200/_cluster/health?level=shards&pretty"

# ノード情報の確認
curl -X GET "localhost:9200/_cat/nodes?v"

# クラスター設定の確認
curl -X GET "localhost:9200/_cluster/settings?pretty"

ノード操作

# すべてのノードをリスト表示
curl -X GET "localhost:9200/_cat/nodes?v&h=name,node.role,heap.percent,ram.percent,cpu,load_1m"

# ノード統計情報
curl -X GET "localhost:9200/_nodes/stats?pretty"

# ホットスレッド(トラブルシューティング用)
curl -X GET "localhost:9200/_nodes/hot_threads"

インデックス管理

インデックスの作成と削除

# インデックスの作成
curl -X PUT "localhost:9200/my_index?pretty"

# 設定付きでインデックスを作成
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}
'

# インデックスの削除
curl -X DELETE "localhost:9200/my_index?pretty"

# すべてのインデックスをリスト表示
curl -X GET "localhost:9200/_cat/indices?v"

# インデックス統計情報
curl -X GET "localhost:9200/my_index/_stats?pretty"

インデックスマッピング

# マッピングの定義
curl -X PUT "localhost:9200/products" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "price": { "type": "float" },
      "created_at": { "type": "date" },
      "tags": { "type": "keyword" },
      "description": { 
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}
'

# マッピングの取得
curl -X GET "localhost:9200/products/_mapping?pretty"

# マッピングの更新(フィールドの追加)
curl -X PUT "localhost:9200/products/_mapping" -H 'Content-Type: application/json' -d'
{
  "properties": {
    "category": { "type": "keyword" }
  }
}
'

インデックステンプレート

# インデックステンプレートの作成
curl -X PUT "localhost:9200/_index_template/logs_template" -H 'Content-Type: application/json' -d'
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 1
    },
    "mappings": {
      "properties": {
        "timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" }
      }
    }
  }
}
'

# テンプレートのリスト表示
curl -X GET "localhost:9200/_index_template?pretty"

ドキュメント操作(CRUD)

ドキュメントの作成

# ID を自動生成してドキュメントをインデックス登録
curl -X POST "localhost:9200/products/_doc?pretty" -H 'Content-Type: application/json' -d'
{
  "name": "Laptop",
  "price": 999.99,
  "tags": ["electronics", "computers"]
}
'

# 特定の ID を指定してドキュメントをインデックス登録
curl -X PUT "localhost:9200/products/_doc/1?pretty" -H 'Content-Type: application/json' -d'
{
  "name": "Laptop",
  "price": 999.99
}
'

# バルクインデックス登録
curl -X POST "localhost:9200/_bulk?pretty" -H 'Content-Type: application/json' -d'
{ "index": { "_index": "products", "_id": "1" }}
{ "name": "Laptop", "price": 999.99 }
{ "index": { "_index": "products", "_id": "2" }}
{ "name": "Mouse", "price": 29.99 }
'

ドキュメントの読み取り

# ID でドキュメントを取得
curl -X GET "localhost:9200/products/_doc/1?pretty"

# 複数のドキュメントを取得
curl -X GET "localhost:9200/_mget?pretty" -H 'Content-Type: application/json' -d'
{
  "docs": [
    { "_index": "products", "_id": "1" },
    { "_index": "products", "_id": "2" }
  ]
}
'

# ドキュメントの存在確認
curl -I "localhost:9200/products/_doc/1"

ドキュメントの更新

# ドキュメントの更新
curl -X POST "localhost:9200/products/_update/1?pretty" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "price": 899.99
  }
}
'

# スクリプトを使用した更新
curl -X POST "localhost:9200/products/_update/1?pretty" -H 'Content-Type: application/json' -d'
{
  "script": {
    "source": "ctx._source.price *= params.discount",
    "params": {
      "discount": 0.9
    }
  }
}
'

# アップサート(更新または挿入)
curl -X POST "localhost:9200/products/_update/1?pretty" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "price": 899.99
  },
  "doc_as_upsert": true
}
'

ドキュメントの削除

# ID による削除
curl -X DELETE "localhost:9200/products/_doc/1?pretty"

# クエリによる削除
curl -X POST "localhost:9200/products/_delete_by_query?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "old"
    }
  }
}
'

検索クエリ

基本的な検索

# すべてに一致
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  }
}
'

# 一致クエリ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "laptop"
    }
  }
}
'

# マルチマッチクエリ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match": {
      "query": "laptop gaming",
      "fields": ["name", "description"]
    }
  }
}
'

用語レベルのクエリ

# 用語クエリ(完全一致)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "term": {
      "tags": "electronics"
    }
  }
}
'

# 複数用語クエリ(複数の値)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "terms": {
      "tags": ["electronics", "computers"]
    }
  }
}
'

# 範囲クエリ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "range": {
      "price": {
        "gte": 100,
        "lte": 1000
      }
    }
  }
}
'

# 存在クエリ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "exists": {
      "field": "description"
    }
  }
}
'

論理演算子クエリ

# Bool クエリ(must, should, must_not, filter)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "laptop" }}
      ],
      "filter": [
        { "range": { "price": { "gte": 500 }}}
      ],
      "should": [
        { "term": { "tags": "gaming" }}
      ],
      "must_not": [
        { "term": { "tags": "refurbished" }}
      ]
    }
  }
}
'

高度な検索

# ワイルドカードクエリ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "wildcard": {
      "name": "lap*"
    }
  }
}
'

# 曖昧一致クエリ(タイプミス許容)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "laptpo",
        "fuzziness": "AUTO"
      }
    }
  }
}
'

# プレフィックスクエリ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "prefix": {
      "name": "lap"
    }
  }
}
'

集計(アグリゲーション)

メトリック集計

# 平均、合計、最小、最大
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "avg_price": { "avg": { "field": "price" }},
    "max_price": { "max": { "field": "price" }},
    "min_price": { "min": { "field": "price" }},
    "total_sales": { "sum": { "field": "price" }}
  }
}
'

# 統計集計
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_stats": {
      "stats": { "field": "price" }
    }
  }
}
'

バケット集計

# 用語集計(グループ化)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "popular_tags": {
      "terms": {
        "field": "tags",
        "size": 10
      }
    }
  }
}
'

# 範囲集計
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 50 },
          { "from": 50, "to": 100 },
          { "from": 100 }
        ]
      }
    }
  }
}
'

# 日付ヒストグラム
curl -X GET "localhost:9200/logs/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "logs_over_time": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      }
    }
  }
}
'

ネストされた集計

# ネストされた集計
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": { "field": "category" },
      "aggs": {
        "avg_price": {
          "avg": { "field": "price" }
        }
      }
    }
  }
}
'

ソートとページネーション

# フィールドによるソート
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "price": { "order": "desc" }},
    { "_score": { "order": "desc" }}
  ]
}
'

# from/size によるページネーション
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "from": 0,
  "size": 10,
  "query": { "match_all": {} }
}
'

# search_after によるページネーション(深いページネーション用)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 10,
  "query": { "match_all": {} },
  "sort": [{ "price": "asc" }, { "_id": "asc" }],
  "search_after": [100, "product_123"]
}
'

フィールド選択とハイライト

# 特定のフィールドを選択
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "_source": ["name", "price"]
}
'

# ハイライト機能
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": { "description": "gaming laptop" }
  },
  "highlight": {
    "fields": {
      "description": {}
    }
  }
}
'

インデックスエイリアス

# エイリアスの作成
curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
  "actions": [
    { "add": { "index": "products_v1", "alias": "products" }}
  ]
}
'

# エイリアスを新しいインデックスに切り替え(ゼロダウンタイム)
curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" }},
    { "add": { "index": "products_v2", "alias": "products" }}
  ]
}
'

# エイリアスのリスト表示
curl -X GET "localhost:9200/_cat/aliases?v"

リインデックス

# 1 つのインデックスから別のインデックスへの再インデックス
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "old_products"
  },
  "dest": {
    "index": "new_products"
  }
}
'

# クエリを使用した再インデックス
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "products",
    "query": {
      "range": {
        "price": { "gte": 100 }
      }
    }
  },
  "dest": {
    "index": "expensive_products"
  }
}
'

スナップショットとバックアップ

# スナップショットリポジトリの登録
curl -X PUT "localhost:9200/_snapshot/my_backup?pretty" -H 'Content-Type: application/json' -d'
{
  "type": "fs",
  "settings": {
    "location": "/mount/backups/my_backup"
  }
}
'

# スナップショットの作成
curl -X PUT "localhost:9200/_snapshot/my_backup/snapshot_1?wait_for_completion=true&pretty"

# スナップショットの復元
curl -X POST "localhost:9200/_snapshot/my_backup/snapshot_1/_restore?pretty"

# スナップショットのリスト表示
curl -X GET "localhost:9200/_snapshot/my_backup/_all?pretty"

# スナップショットの削除
curl -X DELETE "localhost:9200/_snapshot/my_backup/snapshot_1?pretty"

パフォーマンス最適化

インデックス設定

# バルクインデックス登録中のリフレッシュを無効化
curl -X PUT "localhost:9200/products/_settings?pretty" -H 'Content-Type: application/json' -d'
{
  "index": {
    "refresh_interval": "-1"
  }
}
'

# バルクインデックス登録後のリフレッシュを再有効化
curl -X PUT "localhost:9200/products/_settings?pretty" -H 'Content-Type: application/json' -d'
{
  "index": {
    "refresh_interval": "1s"
  }
}
'

# フォースマージ(最適化)
curl -X POST "localhost:9200/products/_forcemerge?max_num_segments=1&pretty"

キャッシュクリア

# すべてのキャッシュをクリア
curl -X POST "localhost:9200/_cache/clear?pretty"

# 特定のキャッシュをクリア
curl -X POST "localhost:9200/products/_cache/clear?query=true&pretty"

モニタリングとトラブルシューティング

# 保留中タスク
curl -X GET "localhost:9200/_cat/pending_tasks?v"

# スレッドプール統計
curl -X GET "localhost:9200/_cat/thread_pool?v"

# セグメント情報
curl -X GET "localhost:9200/_cat/segments?v"

# 復元情報
curl -X GET "localhost:9200/_cat/recovery?v&h=index,stage,time"

# タスク API
curl -X GET "localhost:9200/_tasks?detailed=true&pretty"

Python クライアントの例

from elasticsearch import Elasticsearch

# Elasticsearch への接続
es = Elasticsearch(['http://localhost:9200'])

# ドキュメントのインデックス登録
doc = {
    'name': 'Laptop',
    'price': 999.99,
    'tags': ['electronics']
}
es.index(index='products', id=1, document=doc)

# 検索
resp = es.search(index='products', query={'match': {'name': 'laptop'}})
for hit in resp['hits']['hits']:
    print(hit['_source'])

# バルクインデックス登録
from elasticsearch.helpers import bulk

actions = [
    {
        '_index': 'products',
        '_id': i,
        '_source': {'name': f'Product {i}', 'price': i * 10}
    }
    for i in range(1000)
]
bulk(es, actions)

JavaScript/Node.js クライアントの例

Elasticsearch JavaScript クライアントは、クラスターと対話するための型安全な方法を提供します。本番環境のアプリケーションでは、より良い型安全性と自動補完のために TypeScript を使用することを検討してください。型定義とインターフェースに関するベストプラクティスについては、TypeScript チートシート を参照してください。

const { Client } = require('@elastic/elasticsearch');
const client = new Client({ node: 'http://localhost:9200' });

// ドキュメントのインデックス登録
async function indexDoc() {
  await client.index({
    index: 'products',
    id: 1,
    document: {
      name: 'Laptop',
      price: 999.99
    }
  });
}

// 検索
async function search() {
  const result = await client.search({
    index: 'products',
    query: {
      match: { name: 'laptop' }
    }
  });
  console.log(result.hits.hits);
}

// バルクインデックス登録
async function bulkIndex() {
  const operations = [];
  for (let i = 0; i < 1000; i++) {
    operations.push({ index: { _index: 'products', _id: i } });
    operations.push({ name: `Product ${i}`, price: i * 10 });
  }
  await client.bulk({ operations });
}

強いタイピングを使用した TypeScript の例

import { Client } from '@elastic/elasticsearch';

interface Product {
  name: string;
  price: number;
  tags?: string[];
  created_at?: Date;
}

const client = new Client({ node: 'http://localhost:9200' });

async function indexProduct(product: Product, id: number): Promise<void> {
  await client.index<Product>({
    index: 'products',
    id: id.toString(),
    document: product
  });
}

async function searchProducts(query: string): Promise<Product[]> {
  const result = await client.search<Product>({
    index: 'products',
    query: {
      match: { name: query }
    }
  });
  
  return result.hits.hits.map(hit => hit._source as Product);
}

ベストプラクティス

インデックス設計

  • 最適なパフォーマンスのために、シャードサイズを 20-50GB の範囲に保つ
  • 時系列データにはインデックスライフサイクル管理(ILM)を使用する
  • データをインデックス登録する前にマッピングを慎重に設計する
  • 適切なフィールドタイプを使用する(keyword vs text、日付形式など)
  • 必要ない場合は、大きなドキュメントに対して _source を無効化する

クエリ最適化

  • スコアリングが必要ない場合は、クエリではなくフィルターを使用する
  • 構造化データには用語レベルのクエリを好む
  • bool クエリを使用して、複数の条件を効率的に組み合わせる
  • 深いページネーションには search_after を実装する
  • 頻繁に使用されるフィルターをキャッシュする

インデックス登録パフォーマンス

  • バッチインデックス登録にはバルク API を使用(1 リクエストあたり 1000-5000 ドキュメント)
  • バルク操作中にリフレッシュを無効化する
  • 大量のインデックス登録中は index.refresh_interval を増加させる
  • 並列インデックス登録には複数のスレッド/ワーカーを使用する
  • シャードの分散を改善するためにルーティングの使用を検討する

クラスター管理

  • 定期的にクラスターヘルスを監視する
  • 適切なレプリカ構成を設定する
  • 大規模なクラスターには専用マスターノードを使用する
  • スナップショットを使用した適切なバックアップ戦略を実装する
  • JVM ヒープ使用率を監視(75% 未満に保つ)

セキュリティ

  • 認証と認可を有効にする(X-Pack Security)
  • 本番環境のデプロイでは HTTPS を使用(cURL を --cacert--cert--key オプションで構成して SSL/TLS を設定)
  • 適切なロールベースアクセス制御を実装する
  • 定期的なセキュリティアップデートとパッチ適用
  • 保存時と転送時のデータを暗号化する

一般的なユースケース

フルテキスト検索

Elasticsearch は、以下の機能を持つフルテキスト検索に優れています:

  • 関連性スコアリング
  • 曖昧一致
  • フレーズ一致
  • 類義語の処理
  • 多言語サポート Postgres に検索機能を内蔵すべきか、専用検索エンジンに移行すべきか検討されている場合は、この PostgreSQL フルテキスト検索と Elasticsearch の比較 が、実践的なトレードオフを解説しています。

ログ分析(ELK スタック)

  • Logstash/Filebeat でログを収集
  • Elasticsearch でログをインデックス登録して検索
  • Kibana ダッシュボードで可視化
  • 異常検知のためのアラート設定

E コマース検索

  • 製品カタログ検索
  • 集計を使用したファセットナビゲーション
  • 自動補完と提案
  • パーソナライズされた検索結果

アプリケーションパフォーマンス監視

  • アプリケーションメトリックのインデックス登録
  • リアルタイム監視ダッシュボード
  • 異常検知
  • パフォーマンストレンド分析

参考リンク

公式 Elasticsearch リソース

関連するチートシートとガイド

購読する

システム、インフラ、AIエンジニアリングの新記事をお届けします。