Elasticsearch

分散型RESTful検索・分析エンジン。Apache Luceneベースで、リアルタイム検索、ログ分析、ビジネス分析機能を提供。2024年にAGPLv3ライセンスでオープンソース回帰。

検索エンジン分散フルテキスト検索リアルタイム分析スケーラブルRESTfulNoSQL

Elasticsearch

Elasticsearchは、Apache Luceneベースの分散検索・分析エンジンです。フルテキスト検索、構造化検索、分析機能を備え、大量のデータをリアルタイムで検索・分析できます。RESTful APIを通じてアクセスでき、スケーラブルな分散アーキテクチャを提供します。

主な特徴

分散・スケーラブル

  • 自動シャーディングとレプリケーション
  • ノードの動的追加・削除対応
  • 水平スケーリングによる高可用性
  • 自動負荷分散とフェイルオーバー

高速検索・分析

  • Luceneベースの高性能インデックス
  • リアルタイム検索とNear Real-Time更新
  • 複雑なクエリと集計の高速実行
  • 分散並列処理による高いスループット

豊富な機能

  • フルテキスト検索とファジー検索
  • 地理空間データの検索と分析
  • 時系列データの効率的な処理
  • 機械学習による異常検知

インストール

Ubuntu/Debian

# ElasticsearchのGPGキー追加
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

# リポジトリ追加
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

# インストール
sudo apt update
sudo apt install elasticsearch

# サービス有効化・開始
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch

CentOS/RHEL

# リポジトリ設定
sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

cat <<EOF | sudo tee /etc/yum.repos.d/elasticsearch.repo
[elasticsearch]
name=Elasticsearch repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
EOF

# インストール
sudo yum install --enablerepo=elasticsearch elasticsearch

# サービス有効化・開始
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch

Docker

# 単一ノード構成
docker run --name es01 \
  --net elastic \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  -it docker.elastic.co/elasticsearch/elasticsearch:8.12.0

# データ永続化付き
docker run --name es01 \
  --net elastic \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  -v es_data:/usr/share/elasticsearch/data \
  -it docker.elastic.co/elasticsearch/elasticsearch:8.12.0

Docker Compose

version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - xpack.security.enabled=false
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
      - "9300:9300"
    networks:
      - elastic

volumes:
  es_data:
    driver: local

networks:
  elastic:
    driver: bridge

基本設定

elasticsearch.yml

# クラスタ設定
cluster.name: my-application
node.name: node-1

# ネットワーク設定
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300

# ディスカバリ設定
discovery.type: single-node
# discovery.seed_hosts: ["host1", "host2"]
# cluster.initial_master_nodes: ["node-1", "node-2"]

# パス設定
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch

# メモリ設定
bootstrap.memory_lock: true

# セキュリティ設定
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl:
  enabled: false
xpack.security.transport.ssl:
  enabled: false

# 監視設定
xpack.monitoring.collection.enabled: true

JVM設定 (jvm.options)

# ヒープサイズ(物理メモリの50%以下)
-Xms2g
-Xmx2g

# GCの詳細ログ
-Xlog:gc*,gc+age=trace,safepoint:gc.log:utctime,pid,tags:filecount=32,filesize=64m

基本操作

クラスタ状態確認

# クラスタヘルス確認
curl -X GET "localhost:9200/_cluster/health?pretty"

# ノード情報確認
curl -X GET "localhost:9200/_nodes?pretty"

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

インデックス管理

# インデックス作成
curl -X PUT "localhost:9200/my-index" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 2
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "standard"
      },
      "content": {
        "type": "text",
        "analyzer": "standard"
      },
      "timestamp": {
        "type": "date"
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}'

# インデックス一覧
curl -X GET "localhost:9200/_cat/indices?v"

# インデックス削除
curl -X DELETE "localhost:9200/my-index"

ドキュメント操作

# ドキュメント追加
curl -X POST "localhost:9200/my-index/_doc/1" -H 'Content-Type: application/json' -d'
{
  "title": "Elasticsearch入門",
  "content": "Elasticsearchは強力な検索エンジンです",
  "timestamp": "2024-01-15T10:00:00",
  "location": {
    "lat": 35.6814,
    "lon": 139.7670
  }
}'

# ドキュメント取得
curl -X GET "localhost:9200/my-index/_doc/1"

# ドキュメント更新
curl -X POST "localhost:9200/my-index/_update/1" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "content": "Elasticsearchは非常に強力な検索エンジンです"
  }
}'

# ドキュメント削除
curl -X DELETE "localhost:9200/my-index/_doc/1"

バルク操作

# バルクインサート
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/json' -d'
{"index":{"_index":"my-index","_id":"1"}}
{"title":"記事1","content":"これは最初の記事です","timestamp":"2024-01-15T10:00:00"}
{"index":{"_index":"my-index","_id":"2"}}
{"title":"記事2","content":"これは2番目の記事です","timestamp":"2024-01-15T11:00:00"}
{"index":{"_index":"my-index","_id":"3"}}
{"title":"記事3","content":"これは3番目の記事です","timestamp":"2024-01-15T12:00:00"}
'

検索操作

基本検索

# マッチオール検索
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  }
}'

# テキスト検索
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "content": "Elasticsearch"
    }
  }
}'

# フレーズ検索
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_phrase": {
      "content": "強力な検索エンジン"
    }
  }
}'

高度な検索

# ブール検索
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        {"match": {"title": "Elasticsearch"}}
      ],
      "filter": [
        {"range": {"timestamp": {"gte": "2024-01-01"}}}
      ],
      "must_not": [
        {"match": {"content": "old"}}
      ]
    }
  }
}'

# ファジー検索
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "fuzzy": {
      "title": {
        "value": "Elasticsarch",
        "fuzziness": "AUTO"
      }
    }
  }
}'

# ワイルドカード検索
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "wildcard": {
      "title": "*search*"
    }
  }
}'

集計クエリ

# 基本集計
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "daily_posts": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "1d"
      }
    },
    "avg_score": {
      "avg": {
        "field": "score"
      }
    }
  }
}'

# ネストした集計
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category.keyword"
      },
      "aggs": {
        "avg_views": {
          "avg": {
            "field": "views"
          }
        }
      }
    }
  }
}'

クラスタ構成

3ノードクラスタ設定

# ノード1 (elasticsearch.yml)
cluster.name: production-cluster
node.name: node-1
node.roles: ["master", "data", "ingest"]
network.host: 192.168.1.10
discovery.seed_hosts: ["192.168.1.10", "192.168.1.11", "192.168.1.12"]
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]

# ノード2 (elasticsearch.yml)
cluster.name: production-cluster
node.name: node-2
node.roles: ["master", "data", "ingest"]
network.host: 192.168.1.11
discovery.seed_hosts: ["192.168.1.10", "192.168.1.11", "192.168.1.12"]
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]

# ノード3 (elasticsearch.yml)
cluster.name: production-cluster
node.name: node-3
node.roles: ["master", "data", "ingest"]
network.host: 192.168.1.12
discovery.seed_hosts: ["192.168.1.10", "192.168.1.11", "192.168.1.12"]
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]

専用ノード構成

# マスターノード
node.roles: ["master"]

# データノード
node.roles: ["data", "data_content", "data_hot", "data_warm", "data_cold"]

# Ingestノード
node.roles: ["ingest"]

# 検索専用ノード
node.roles: ["search"]

# 機械学習ノード
node.roles: ["ml", "remote_cluster_client"]

インデックス設定

マッピング定義

# 詳細マッピング設定
curl -X PUT "localhost:9200/products" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": ["lowercase", "stop"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "standard",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "description": {
        "type": "text",
        "analyzer": "my_analyzer"
      },
      "price": {
        "type": "double"
      },
      "created_date": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "tags": {
        "type": "keyword"
      },
      "location": {
        "type": "geo_point"
      },
      "metadata": {
        "type": "object",
        "properties": {
          "category": {"type": "keyword"},
          "brand": {"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,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs_policy"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "level": {
          "type": "keyword"
        },
        "message": {
          "type": "text"
        },
        "source": {
          "type": "keyword"
        }
      }
    }
  }
}'

パフォーマンス最適化

検索パフォーマンス

# プロファイル有効化
curl -X GET "localhost:9200/my-index/_search" -H 'Content-Type: application/json' -d'
{
  "profile": true,
  "query": {
    "match": {
      "content": "Elasticsearch"
    }
  }
}'

# 検索実行計画確認
curl -X GET "localhost:9200/my-index/_validate/query?explain" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        {"match": {"title": "search"}},
        {"range": {"timestamp": {"gte": "2024-01-01"}}}
      ]
    }
  }
}'

インデックス最適化

# インデックス最適化
curl -X POST "localhost:9200/my-index/_forcemerge?max_num_segments=1"

# インデックス統計確認
curl -X GET "localhost:9200/my-index/_stats"

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

キャッシュ設定

# elasticsearch.yml
indices.queries.cache.size: 10%
indices.fielddata.cache.size: 40%
indices.requests.cache.size: 1%

監視とメンテナンス

ヘルスチェック

# クラスタヘルス詳細
curl -X GET "localhost:9200/_cluster/health?level=indices&pretty"

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

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

# タスク確認
curl -X GET "localhost:9200/_tasks?detailed&pretty"

ログ分析

# スローログ設定
curl -X PUT "localhost:9200/my-index/_settings" -H 'Content-Type: application/json' -d'
{
  "index.search.slowlog.threshold.query.warn": "10s",
  "index.search.slowlog.threshold.query.info": "5s",
  "index.search.slowlog.threshold.query.debug": "2s",
  "index.search.slowlog.threshold.query.trace": "500ms",
  "index.indexing.slowlog.threshold.index.warn": "10s",
  "index.indexing.slowlog.threshold.index.info": "5s"
}'

バックアップ・リストア

# スナップショットリポジトリ作成
curl -X PUT "localhost:9200/_snapshot/my_backup" -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" -H 'Content-Type: application/json' -d'
{
  "indices": "my-index",
  "ignore_unavailable": true,
  "include_global_state": false
}'

# スナップショットからリストア
curl -X POST "localhost:9200/_snapshot/my_backup/snapshot_1/_restore" -H 'Content-Type: application/json' -d'
{
  "indices": "my-index",
  "ignore_unavailable": true,
  "include_global_state": false
}'

セキュリティ設定

# 基本認証有効化
bin/elasticsearch-setup-passwords auto

# APIキー作成
curl -X POST "localhost:9200/_security/api_key" -u elastic:password -H 'Content-Type: application/json' -d'
{
  "name": "my-api-key",
  "role_descriptors": {
    "my_role": {
      "cluster": ["monitor"],
      "indices": [
        {
          "names": ["my-index"],
          "privileges": ["read", "write"]
        }
      ]
    }
  }
}'

Elasticsearchは、その柔軟性と高性能により、ログ分析、検索システム、リアルタイム分析、ビジネスインテリジェンスなど様々な用途で活用されています。適切な設計と設定により、大規模なデータでも高速な検索・分析を実現できます。