データベース
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"