Elasticsearch

分散型RESTful検索・分析エンジン。全文検索、ログ分析、メトリクス分析に特化。リアルタイム検索とスケーラビリティが特徴。

データベースサーバー検索エンジン分散システムNoSQLリアルタイム検索分析エンジンログ分析AI・機械学習対応

データベースサーバー

Elasticsearch

概要

Elasticsearchは、分散型のリアルタイム検索・分析エンジンで、Apache Luceneをベースに構築された高性能なNoSQLデータベースです。2010年にElastic N.V.によって開発され、現在では世界中で幅広く採用されている検索・分析プラットフォームの中核を担っています。大規模なデータセットに対するミリ秒レベルの高速検索、リアルタイム分析、ベクトル検索、生成AI統合など、現代のデータドリブンアプリケーションに求められる機能を包括的に提供します。RESTful APIによる直感的な操作性と、水平スケーリングによる無制限の拡張性により、スタートアップから大企業まで、あらゆる規模の組織でミッションクリティカルなシステムの基盤として活用されています。

詳細

Elasticsearch 2025年版は、生成AI時代のデータ分析基盤として大幅に進化しています。最新バージョンでは、RAG(Retrieval Augmented Generation)のネイティブサポート、高精度ベクトル検索、リアルタイムストリーミング分析、セキュリティ分析SIEM機能が統合され、従来の検索エンジンの枠を超えた包括的なデータプラットフォームとして機能します。Elastic Cloudでのマネージドサービス提供により、インフラ管理の負担を最小化しながら企業レベルの可用性・セキュリティを実現。Docker、Kubernetes、オンプレミス、マルチクラウド環境での柔軟な展開が可能で、数テラバイトから数ペタバイトまでのデータ量に対応します。Machine Learning機能による異常検知、トレンド予測、自動化された運用最適化により、単なるデータストレージを超えた知的データプラットフォームとしての価値を提供しています。

主な特徴

  • 分散アーキテクチャ: 自動シャーディングとレプリケーションによる高可用性とスケーラビリティ
  • リアルタイム検索: ミリ秒レベルの高速全文検索とファセット検索
  • ベクトル検索: AI・機械学習モデルとの統合による意味的検索
  • RESTful API: HTTPベースの直感的なAPI設計
  • 多様なデータ型: テキスト、数値、地理情報、時系列、JSONなど包括的サポート
  • Elastic Stack統合: Kibana、Logstash、Beatsとの完全統合エコシステム

メリット・デメリット

メリット

  • 大規模データに対する極めて高速な検索・分析性能
  • スキーマレス設計による柔軟なデータモデリングと迅速な開発
  • 水平スケーリングによる事実上無制限の拡張性
  • 豊富なクエリDSLとアグリゲーション機能による高度な分析
  • Elastic Stackエコシステムによる包括的なデータパイプライン構築
  • アクティブなオープンソースコミュニティと企業サポート

デメリット

  • 分散システムの複雑性による運用・設定の学習コスト
  • リアルタイム性重視のためACIDトランザクションサポートの制限
  • 大量データでのメモリ使用量とストレージコストの高さ
  • クラスター設計ミスによる性能問題やデータロスリスク
  • 商用機能の高ライセンス費用(Elastic License制限)
  • レプリケーション遅延によるデータ整合性の一時的な課題

参考ページ

書き方の例

インストールと基本セットアップ

# Docker Composeを使用した環境構築
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms2g -Xmx2g
      - xpack.security.enabled=false  # 開発環境用
      - cluster.name=docker-cluster
      - node.name=es01
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
      - "9300:9300"
    restart: unless-stopped

  kibana:
    image: docker.elastic.co/kibana/kibana:8.15.0
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - SERVER_NAME=kibana
      - SERVER_HOST=0.0.0.0
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    restart: unless-stopped

volumes:
  es_data:
    driver: local
EOF

# サービス起動
docker-compose up -d

# 動作確認
curl http://localhost:9200
curl http://localhost:9200/_cluster/health

# Linux環境でのネイティブインストール
# Elastic公式リポジトリ追加
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

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

# 設定ファイル編集
sudo nano /etc/elasticsearch/elasticsearch.yml

# 基本設定例
cat > /etc/elasticsearch/elasticsearch.yml << 'EOF'
cluster.name: my-cluster
node.name: node-1
network.host: 0.0.0.0
http.port: 9200
discovery.type: single-node
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
EOF

# サービス開始
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch.service
sudo systemctl start elasticsearch.service
sudo systemctl status elasticsearch.service

基本的なインデックス操作とデータ管理

# インデックス作成(マッピング定義付き)
curl -X PUT "localhost:9200/products" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "standard"
      },
      "description": {
        "type": "text",
        "analyzer": "japanese"
      },
      "price": {
        "type": "double"
      },
      "category": {
        "type": "keyword"
      },
      "tags": {
        "type": "keyword"
      },
      "created_at": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "location": {
        "type": "geo_point"
      },
      "stock_count": {
        "type": "integer"
      },
      "is_active": {
        "type": "boolean"
      }
    }
  },
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index": {
      "refresh_interval": "1s"
    }
  }
}'

# ドキュメント挿入(単一)
curl -X POST "localhost:9200/products/_doc/1" -H 'Content-Type: application/json' -d'
{
  "name": "MacBook Pro 16インチ",
  "description": "Apple M3 Max搭載の高性能ノートパソコン",
  "price": 398000,
  "category": "laptop",
  "tags": ["apple", "m3", "professional"],
  "created_at": "2025-01-15 10:30:00",
  "location": {
    "lat": 35.6762,
    "lon": 139.6503
  },
  "stock_count": 15,
  "is_active": true
}'

# バルク挿入
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/json' -d'
{ "index" : { "_index" : "products", "_id" : "2" } }
{ "name": "ThinkPad X1 Carbon", "description": "軽量ビジネスノートPC", "price": 289000, "category": "laptop", "tags": ["lenovo", "business"], "created_at": "2025-01-15 11:00:00", "stock_count": 8, "is_active": true }
{ "index" : { "_index" : "products", "_id" : "3" } }
{ "name": "iPhone 15 Pro", "description": "最新のiPhoneモデル", "price": 159800, "category": "smartphone", "tags": ["apple", "5g"], "created_at": "2025-01-15 11:15:00", "stock_count": 25, "is_active": true }
{ "index" : { "_index" : "products", "_id" : "4" } }
{ "name": "Surface Pro 9", "description": "2-in-1タブレットPC", "price": 189800, "category": "tablet", "tags": ["microsoft", "2in1"], "created_at": "2025-01-15 11:30:00", "stock_count": 12, "is_active": true }
'

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

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

# インデックス情報確認
curl -X GET "localhost:9200/products"
curl -X GET "localhost:9200/products/_mapping"
curl -X GET "localhost:9200/products/_settings"

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

高度な検索クエリとアグリゲーション

# 基本的な全文検索
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "description": "ノートパソコン"
    }
  }
}'

# 複合検索クエリ(bool query)
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "range": { "price": { "gte": 100000, "lte": 300000 } } }
      ],
      "should": [
        { "match": { "name": "MacBook" } },
        { "match": { "name": "ThinkPad" } }
      ],
      "filter": [
        { "term": { "category": "laptop" } },
        { "term": { "is_active": true } }
      ],
      "must_not": [
        { "range": { "stock_count": { "lte": 5 } } }
      ]
    }
  },
  "sort": [
    { "price": { "order": "desc" } },
    { "created_at": { "order": "desc" } }
  ],
  "size": 10,
  "from": 0
}'

# ファジー検索とワイルドカード検索
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "should": [
        {
          "fuzzy": {
            "name": {
              "value": "MacBok",
              "fuzziness": "AUTO"
            }
          }
        },
        {
          "wildcard": {
            "name": "*Book*"
          }
        }
      ]
    }
  }
}'

# アグリゲーション分析
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category",
        "size": 10
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        },
        "max_price": {
          "max": {
            "field": "price"
          }
        },
        "total_stock": {
          "sum": {
            "field": "stock_count"
          }
        }
      }
    },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 100000 },
          { "from": 100000, "to": 200000 },
          { "from": 200000, "to": 300000 },
          { "from": 300000 }
        ]
      }
    },
    "daily_sales": {
      "date_histogram": {
        "field": "created_at",
        "calendar_interval": "day",
        "format": "yyyy-MM-dd"
      }
    }
  }
}'

# 地理的検索(geo distance)
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "geo_distance": {
      "distance": "10km",
      "location": {
        "lat": 35.6762,
        "lon": 139.6503
      }
    }
  }
}'

インデックステンプレートとライフサイクル管理

# インデックステンプレート作成
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",
      "index.lifecycle.rollover_alias": "logs-alias"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "level": {
          "type": "keyword"
        },
        "message": {
          "type": "text",
          "analyzer": "standard"
        },
        "service": {
          "type": "keyword"
        },
        "host": {
          "type": "keyword"
        },
        "request_id": {
          "type": "keyword"
        }
      }
    }
  },
  "priority": 100
}'

# ILM(Index Lifecycle Management)ポリシー作成
curl -X PUT "localhost:9200/_ilm/policy/logs_policy" -H 'Content-Type: application/json' -d'
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "10GB",
            "max_age": "7d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "set_priority": {
            "priority": 50
          },
          "allocate": {
            "number_of_replicas": 0
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}'

# エイリアス作成
curl -X PUT "localhost:9200/logs-000001" -H 'Content-Type: application/json' -d'
{
  "aliases": {
    "logs-alias": {
      "is_write_index": true
    }
  }
}'

# スナップショット設定
curl -X PUT "localhost:9200/_snapshot/backup_repository" -H 'Content-Type: application/json' -d'
{
  "type": "fs",
  "settings": {
    "location": "/usr/share/elasticsearch/backup",
    "compress": true
  }
}'

# スナップショット作成
curl -X PUT "localhost:9200/_snapshot/backup_repository/snapshot_1" -H 'Content-Type: application/json' -d'
{
  "indices": "products,logs-*",
  "ignore_unavailable": true,
  "include_global_state": false
}'

パフォーマンス最適化とモニタリング

# クラスター健康状態確認
curl -X GET "localhost:9200/_cluster/health?pretty"
curl -X GET "localhost:9200/_cluster/stats?pretty"
curl -X GET "localhost:9200/_nodes/stats?pretty"

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

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

# インデックス設定の動的更新
curl -X PUT "localhost:9200/products/_settings" -H 'Content-Type: application/json' -d'
{
  "index": {
    "refresh_interval": "30s",
    "number_of_replicas": 2,
    "max_result_window": 50000
  }
}'

# スロークエリログ設定
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
  "persistent": {
    "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.fetch.warn": "1s"
  }
}'

# プロファイリング付きクエリ実行
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "profile": true,
  "query": {
    "bool": {
      "must": [
        { "match": { "description": "ノートパソコン" } }
      ],
      "filter": [
        { "range": { "price": { "gte": 200000 } } }
      ]
    }
  }
}'

# ホットスレッド分析
curl -X GET "localhost:9200/_nodes/hot_threads"

# タスク管理
curl -X GET "localhost:9200/_tasks?detailed=true&actions=*search*"

# メモリ使用量確認
curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"

セキュリティとアクセス制御

# セキュリティ設定有効化(elasticsearch.yml)
cat >> /etc/elasticsearch/elasticsearch.yml << 'EOF'
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.http.ssl.enabled: true
EOF

# 内蔵ユーザーのパスワード設定
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive

# ロール作成
curl -X POST "localhost:9200/_security/role/products_read_only" -H 'Content-Type: application/json' -u elastic:password -d'
{
  "cluster": [],
  "indices": [
    {
      "names": [ "products" ],
      "privileges": [ "read" ],
      "field_security": {
        "grant": [ "name", "description", "price", "category" ]
      }
    }
  ]
}'

# ユーザー作成
curl -X POST "localhost:9200/_security/user/product_viewer" -H 'Content-Type: application/json' -u elastic:password -d'
{
  "password" : "product123",
  "roles" : [ "products_read_only" ],
  "full_name" : "Product Viewer",
  "email" : "[email protected]"
}'

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

# IP許可リスト設定
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -u elastic:password -d'
{
  "persistent": {
    "xpack.security.http.filter.allow": "192.168.1.0/24,10.0.0.0/8",
    "xpack.security.http.filter.deny": "_all"
  }
}'

アプリケーション統合例

# Python Elasticsearchクライアント
from elasticsearch import Elasticsearch
from datetime import datetime
import json

class ElasticsearchManager:
    def __init__(self, hosts=['localhost:9200'], **kwargs):
        """Elasticsearchクライアント初期化"""
        self.es = Elasticsearch(
            hosts=hosts,
            # 認証設定
            basic_auth=('elastic', 'password'),  # 基本認証
            # api_key=('id', 'api_key'),         # APIキー認証
            
            # SSL設定
            verify_certs=False,
            ssl_show_warn=False,
            
            # 接続設定
            timeout=30,
            max_retries=3,
            retry_on_timeout=True,
            **kwargs
        )
    
    def check_connection(self):
        """接続確認"""
        try:
            info = self.es.info()
            print(f"Elasticsearch接続成功: {info['version']['number']}")
            return True
        except Exception as e:
            print(f"接続エラー: {e}")
            return False
    
    def create_index(self, index_name, mapping=None, settings=None):
        """インデックス作成"""
        body = {}
        if mapping:
            body['mappings'] = mapping
        if settings:
            body['settings'] = settings
        
        try:
            if not self.es.indices.exists(index=index_name):
                self.es.indices.create(index=index_name, body=body)
                print(f"インデックス '{index_name}' を作成しました")
            else:
                print(f"インデックス '{index_name}' は既に存在します")
        except Exception as e:
            print(f"インデックス作成エラー: {e}")
    
    def index_document(self, index_name, doc_id, document):
        """ドキュメント挿入"""
        try:
            result = self.es.index(
                index=index_name,
                id=doc_id,
                body=document
            )
            return result
        except Exception as e:
            print(f"ドキュメント挿入エラー: {e}")
            return None
    
    def bulk_index(self, index_name, documents):
        """バルク挿入"""
        from elasticsearch.helpers import bulk
        
        actions = []
        for doc_id, document in documents.items():
            action = {
                '_index': index_name,
                '_id': doc_id,
                '_source': document
            }
            actions.append(action)
        
        try:
            result = bulk(self.es, actions)
            print(f"バルク挿入完了: {result[0]}件成功")
            return result
        except Exception as e:
            print(f"バルク挿入エラー: {e}")
            return None
    
    def search(self, index_name, query, size=10, from_=0, sort=None):
        """検索実行"""
        body = {
            'query': query,
            'size': size,
            'from': from_
        }
        
        if sort:
            body['sort'] = sort
        
        try:
            result = self.es.search(index=index_name, body=body)
            return result
        except Exception as e:
            print(f"検索エラー: {e}")
            return None
    
    def aggregate(self, index_name, aggregations, query=None):
        """アグリゲーション実行"""
        body = {
            'size': 0,
            'aggs': aggregations
        }
        
        if query:
            body['query'] = query
        
        try:
            result = self.es.search(index=index_name, body=body)
            return result['aggregations']
        except Exception as e:
            print(f"アグリゲーションエラー: {e}")
            return None

# 実装例
if __name__ == "__main__":
    # Elasticsearchマネージャー初期化
    es_manager = ElasticsearchManager()
    
    # 接続確認
    if not es_manager.check_connection():
        exit(1)
    
    # インデックス作成
    product_mapping = {
        'properties': {
            'name': {'type': 'text', 'analyzer': 'standard'},
            'description': {'type': 'text', 'analyzer': 'japanese'},
            'price': {'type': 'double'},
            'category': {'type': 'keyword'},
            'tags': {'type': 'keyword'},
            'created_at': {'type': 'date'},
            'stock_count': {'type': 'integer'},
            'is_active': {'type': 'boolean'}
        }
    }
    
    es_manager.create_index('products', mapping=product_mapping)
    
    # サンプルデータ挿入
    sample_products = {
        '1': {
            'name': 'MacBook Pro 16インチ',
            'description': 'Apple M3 Max搭載の高性能ノートパソコン',
            'price': 398000,
            'category': 'laptop',
            'tags': ['apple', 'm3', 'professional'],
            'created_at': datetime.now().isoformat(),
            'stock_count': 15,
            'is_active': True
        },
        '2': {
            'name': 'ThinkPad X1 Carbon',
            'description': '軽量ビジネスノートPC',
            'price': 289000,
            'category': 'laptop',
            'tags': ['lenovo', 'business'],
            'created_at': datetime.now().isoformat(),
            'stock_count': 8,
            'is_active': True
        }
    }
    
    es_manager.bulk_index('products', sample_products)
    
    # 検索実行
    search_query = {
        'bool': {
            'must': [
                {'match': {'description': 'ノートパソコン'}}
            ],
            'filter': [
                {'range': {'price': {'gte': 200000}}}
            ]
        }
    }
    
    results = es_manager.search('products', search_query)
    print(f"検索結果: {results['hits']['total']['value']}件")
    
    # アグリゲーション実行
    aggs = {
        'categories': {
            'terms': {
                'field': 'category',
                'size': 10
            },
            'aggs': {
                'avg_price': {
                    'avg': {'field': 'price'}
                }
            }
        }
    }
    
    agg_results = es_manager.aggregate('products', aggs)
    print(f"アグリゲーション結果: {json.dumps(agg_results, indent=2, ensure_ascii=False)}")