データベース

Elasticsearch

概要

Elasticsearchは、分散型でRESTfulな検索・分析エンジンです。Apache Luceneをベースに構築され、リアルタイムでの全文検索、構造化データ検索、分析機能を提供します。JSON形式でドキュメントを格納し、HTTP APIを通じてアクセスできるため、多様なアプリケーションで検索機能を簡単に実装できます。

詳細

Elasticsearchは2010年にShay Banon氏によって開発され、現在はElastic N.V.が開発・保守しています。水平スケーリングに優れ、複数のノードでクラスターを構成してペタバイト規模のデータも処理可能です。ELKスタック(Elasticsearch、Logstash、Kibana)の中核コンポーネントとして、ログ分析やメトリクス監視に広く使用されています。

Elasticsearchの主な特徴:

  • 分散型アーキテクチャ
  • リアルタイム検索・分析
  • RESTful HTTP API
  • スキーマフリー(JSON)
  • 強力なクエリDSL
  • ファセット検索・集約機能
  • 地理空間検索
  • 機械学習機能
  • 高可用性・自動フェイルオーバー
  • 水平スケーリング

メリット・デメリット

メリット

  • 高速検索: 逆インデックスによる高速な全文検索
  • スケーラビリティ: 水平スケーリングで大量データに対応
  • リアルタイム: ほぼリアルタイムでの検索・分析
  • 豊富なAPI: RESTful APIによる簡単なアクセス
  • 柔軟性: スキーマレスでの動的なフィールド追加
  • 分析機能: 強力な集約(Aggregations)機能
  • エコシステム: Kibana、Logstashとの連携

デメリット

  • リソース消費: メモリとディスクを大量に消費
  • 複雑性: 設定・チューニングが複雑
  • 一貫性: 最終的整合性(ACID特性は限定的)
  • バックアップ: 大容量データのバックアップが困難
  • ライセンス: 一部の機能は有償(Elastic License)

主要リンク

書き方の例

インストール・セットアップ

# Docker での実行(推奨)
docker run -d --name elasticsearch \
  -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
  docker.elastic.co/elasticsearch/elasticsearch:8.11.0

# Ubuntu/Debian
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb 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

# Red Hat/CentOS
sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
cat > /etc/yum.repos.d/elasticsearch.repo << EOF
[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

# macOS (Homebrew)
brew tap elastic/tap
brew install elastic/tap/elasticsearch-full

# サービス起動
sudo systemctl start elasticsearch
sudo systemctl enable elasticsearch

# 起動確認
curl -X GET "localhost:9200/"

基本操作(CRUD)

# インデックス作成
curl -X PUT "localhost:9200/products" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "name": { "type": "text", "analyzer": "standard" },
      "description": { "type": "text" },
      "price": { "type": "double" },
      "category": { "type": "keyword" },
      "created_at": { "type": "date" },
      "tags": { "type": "keyword" },
      "location": { "type": "geo_point" }
    }
  }
}'

# ドキュメント作成(Create)
curl -X POST "localhost:9200/products/_doc/1" -H 'Content-Type: application/json' -d'
{
  "name": "ワイヤレスイヤホン",
  "description": "高音質Bluetooth対応イヤホン",
  "price": 8900,
  "category": "電子機器",
  "created_at": "2024-01-15T10:30:00Z",
  "tags": ["audio", "wireless", "bluetooth"],
  "location": { "lat": 35.6762, "lon": 139.6503 }
}'

# 自動ID生成でドキュメント作成
curl -X POST "localhost:9200/products/_doc" -H 'Content-Type: application/json' -d'
{
  "name": "スマートフォン",
  "description": "最新5G対応スマートフォン",
  "price": 89000,
  "category": "電子機器",
  "created_at": "2024-01-16T14:20:00Z",
  "tags": ["smartphone", "5g", "mobile"]
}'

# ドキュメント読み取り(Read)
curl -X GET "localhost:9200/products/_doc/1"

# ドキュメント更新(Update)
curl -X POST "localhost:9200/products/_update/1" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "price": 7900,
    "tags": ["audio", "wireless", "bluetooth", "sale"]
  }
}'

# スクリプトによる更新
curl -X POST "localhost:9200/products/_update/1" -H 'Content-Type: application/json' -d'
{
  "script": {
    "source": "ctx._source.price = ctx._source.price * 0.9"
  }
}'

# ドキュメント削除(Delete)
curl -X DELETE "localhost:9200/products/_doc/1"

検索クエリ

# シンプル検索
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "イヤホン"
    }
  }
}'

# 複合検索(Bool Query)
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "スマートフォン" } }
      ],
      "filter": [
        { "range": { "price": { "gte": 50000, "lte": 100000 } } },
        { "term": { "category": "電子機器" } }
      ],
      "must_not": [
        { "term": { "tags": "discontinued" } }
      ]
    }
  },
  "sort": [
    { "price": { "order": "asc" } },
    { "created_at": { "order": "desc" } }
  ],
  "size": 10,
  "from": 0
}'

# ワイルドカード検索
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "wildcard": {
      "name": "*イヤホン*"
    }
  }
}'

# ファジー検索(曖昧検索)
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "スマートホン",
        "fuzziness": "AUTO"
      }
    }
  }
}'

# 地理的検索
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 GET "localhost:9200/_cat/indices?v"

# インデックス情報取得
curl -X GET "localhost:9200/products"

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

# インデックステンプレート作成
curl -X PUT "localhost:9200/_index_template/products_template" -H 'Content-Type: application/json' -d'
{
  "index_patterns": ["products-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    },
    "mappings": {
      "properties": {
        "name": { "type": "text" },
        "price": { "type": "double" },
        "created_at": { "type": "date" }
      }
    }
  }
}'

# バルクインデックス
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/json' -d'
{ "index" : { "_index" : "products", "_id" : "2" } }
{ "name" : "ノートPC", "price" : 89000, "category" : "コンピュータ" }
{ "index" : { "_index" : "products", "_id" : "3" } }
{ "name" : "マウス", "price" : 2900, "category" : "周辺機器" }
{ "update" : { "_index" : "products", "_id" : "1" } }
{ "doc" : { "price" : 8500 } }
{ "delete" : { "_index" : "products", "_id" : "4" } }
'

集約(Aggregations)

# カテゴリ別集計
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category",
        "size": 10
      }
    }
  }
}'

# 価格帯別統計
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_stats": {
      "stats": {
        "field": "price"
      }
    },
    "price_histogram": {
      "histogram": {
        "field": "price",
        "interval": 10000
      }
    }
  }
}'

# 日付ヒストグラム
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "sales_over_time": {
      "date_histogram": {
        "field": "created_at",
        "calendar_interval": "1M",
        "format": "yyyy-MM"
      }
    }
  }
}'

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

実用例

# 全文検索とハイライト
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match": {
      "query": "高音質 ワイヤレス",
      "fields": ["name^2", "description"],
      "type": "best_fields"
    }
  },
  "highlight": {
    "fields": {
      "name": {},
      "description": {}
    }
  }
}'

# 検索候補(Suggestions)
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "suggest": {
    "my_suggestion": {
      "text": "イヤホ",
      "term": {
        "field": "name"
      }
    }
  }
}'

# 複数インデックス検索
curl -X GET "localhost:9200/products,users/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  }
}'

# スクロール検索(大量データ)
curl -X GET "localhost:9200/products/_search?scroll=1m" -H 'Content-Type: application/json' -d'
{
  "size": 1000,
  "query": {
    "match_all": {}
  }
}'

# 結果フィルタリング
curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  },
  "_source": ["name", "price", "category"]
}'

分析とマッピング

# アナライザーの作成
curl -X PUT "localhost:9200/japanese_products" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "analysis": {
      "analyzer": {
        "japanese_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_tokenizer",
          "filter": [
            "kuromoji_baseform",
            "kuromoji_part_of_speech",
            "ja_stop",
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "japanese_analyzer"
      },
      "description": {
        "type": "text",
        "analyzer": "japanese_analyzer"
      }
    }
  }
}'

# 動的マッピングテンプレート
curl -X PUT "localhost:9200/dynamic_products" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "dynamic_templates": [
      {
        "strings_as_keywords": {
          "match_mapping_type": "string",
          "match": "*_id",
          "mapping": {
            "type": "keyword"
          }
        }
      },
      {
        "strings_as_text": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "text",
            "fields": {
              "raw": {
                "type": "keyword"
              }
            }
          }
        }
      }
    ]
  }
}'

パフォーマンス最適化

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

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

# キャッシュクリア
curl -X POST "localhost:9200/products/_cache/clear"

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

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

# クラスター健康状態
curl -X GET "localhost:9200/_cluster/health"

機械学習とパイプライン

# 取り込みパイプライン作成
curl -X PUT "localhost:9200/_ingest/pipeline/product_pipeline" -H 'Content-Type: application/json' -d'
{
  "description": "product data processing pipeline",
  "processors": [
    {
      "set": {
        "field": "processed_at",
        "value": "{{_ingest.timestamp}}"
      }
    },
    {
      "uppercase": {
        "field": "category"
      }
    },
    {
      "script": {
        "source": "ctx.price_category = ctx.price > 50000 ? \"high\" : \"low\""
      }
    }
  ]
}'

# パイプラインを使った取り込み
curl -X POST "localhost:9200/products/_doc?pipeline=product_pipeline" -H 'Content-Type: application/json' -d'
{
  "name": "タブレット",
  "price": 65000,
  "category": "electronics"
}'

クラスター管理

# シャード配置確認
curl -X GET "localhost:9200/_cat/shards/products?v"

# ノード一覧
curl -X GET "localhost:9200/_cat/nodes?v"

# インデックスの再配置
curl -X POST "localhost:9200/_cluster/reroute" -H 'Content-Type: application/json' -d'
{
  "commands": [
    {
      "move": {
        "index": "products",
        "shard": 0,
        "from_node": "node1",
        "to_node": "node2"
      }
    }
  ]
}'

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

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