OpenSearch

Elasticsearchのオープンソースフォーク。分散検索・分析エンジンで、ログ分析、リアルタイム監視、セキュリティ分析に対応。AWS主導で開発。

Search EngineOpen SourceDistributedAWSElasticsearch ForkAnalyticsVector SearchReal-time

サーバー

OpenSearch

概要

OpenSearchは、AWS主導によるElasticsearchのフォークから誕生したオープンソースの分散検索・分析エンジンです。2024年にLinux Foundationの管理下に移行し、1,400名以上の貢献者と100以上のGitHubリポジトリを持つ大規模なコミュニティプロジェクトへと発展しました。ベクトル検索、ハイブリッド検索、AI駆動の検索機能を特徴とし、AWS環境での統合性に優れています。

詳細

OpenSearch 2024版では、Elasticsearchとの単純な互換性を超えて独自のアイデンティティを確立しています。FacebookのFAISS統合、SIMD硬件加速、ベクトル量子化による高性能セマンティック検索、クロスクラスターレプリケーション、トレース分析、データストリーム、変換機能、新しい可観測性UI、k-NN、異常検出、PPL、SQL、アラート機能の大幅な改善が実装されています。AWS IAM、KMS、CloudWatchとのネイティブ統合により、AWS環境での運用に最適化されています。

主要機能

  • ベクトル・ハイブリッド検索: セマンティック検索とキーワード検索を組み合わせた次世代検索
  • 分散アーキテクチャ: 水平スケーリングと高可用性を実現する分散設計
  • AWS統合: IAM、KMS、CloudWatchとのネイティブ統合
  • 可観測性: 包括的なトレース分析とモニタリング機能
  • AI・機械学習: 組み込み異常検出とニューラル検索機能
  • リアルタイム分析: ストリーミングデータの即座な分析とアラート

メリット・デメリット

メリット

  • Linux Foundation管理によるオープンガバナンスと長期的な安定性
  • AWS環境での優れた統合性とマネージドサービス(Amazon OpenSearch Service)
  • ベクトル検索やAI機能による次世代ワークロードのサポート
  • Elasticsearchライセンス問題からの解放と真のオープンソース
  • 活発なコミュニティ(1,400+貢献者)による継続的な開発
  • AWS独自プラグインと機能の豊富なライブラリ

デメリット

  • エンタープライズスケールや複雑なクエリでElasticsearchにパフォーマンス劣る場合がある
  • Elasticsearchと比較してプラグインエコシステムが限定的
  • AWS外での運用ではElasticsearchの方が成熟したツールチェーンを持つ
  • 移行時にElasticsearchとの完全互換性に課題がある場合がある
  • 一部の高度なElastic Stack機能が利用できない
  • 商用サポートオプションがElasticsearchほど豊富ではない

参考ページ

書き方の例

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

# Dockerでの実行
docker run -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" opensearchproject/opensearch:latest

# Docker Composeでのクラスター構成
cat > docker-compose.yml << 'EOF'
version: '3'
services:
  opensearch-node1:
    image: opensearchproject/opensearch:latest
    container_name: opensearch-node1
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node1
      - discovery.seed_hosts=opensearch-node1,opensearch-node2
      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearch-data1:/usr/share/opensearch/data
    ports:
      - 9200:9200
      - 9600:9600
    networks:
      - opensearch-net
      
  opensearch-node2:
    image: opensearchproject/opensearch:latest
    container_name: opensearch-node2
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node2
      - discovery.seed_hosts=opensearch-node1,opensearch-node2
      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearch-data2:/usr/share/opensearch/data
    networks:
      - opensearch-net

  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:latest
    container_name: opensearch-dashboards
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      OPENSEARCH_HOSTS: '["https://opensearch-node1:9200","https://opensearch-node2:9200"]'
    networks:
      - opensearch-net

volumes:
  opensearch-data1:
  opensearch-data2:

networks:
  opensearch-net:
EOF

docker-compose up -d

# Linux環境でのバイナリインストール
wget https://artifacts.opensearch.org/releases/bundle/opensearch/2.11.1/opensearch-2.11.1-linux-x64.tar.gz
tar -xzf opensearch-2.11.1-linux-x64.tar.gz
cd opensearch-2.11.1

# 設定ファイルの編集
vi config/opensearch.yml

# OpenSearchの起動
./bin/opensearch

インデックス作成とドキュメント管理

# インデックス作成
curl -X PUT "localhost:9200/movies" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 1
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "standard"
      },
      "overview": {
        "type": "text",
        "analyzer": "standard"
      },
      "genre": {
        "type": "keyword"
      },
      "release_date": {
        "type": "date"
      },
      "rating": {
        "type": "float"
      },
      "location": {
        "type": "geo_point"
      },
      "embedding": {
        "type": "knn_vector",
        "dimension": 512,
        "method": {
          "name": "hnsw",
          "space_type": "l2",
          "engine": "nmslib"
        }
      }
    }
  }
}'

# 単一ドキュメント追加
curl -X POST "localhost:9200/movies/_doc/1" -H 'Content-Type: application/json' -d'
{
  "title": "アベンジャーズ/エンドゲーム",
  "overview": "マーベル・シネマティック・ユニバースの壮大な結末",
  "genre": ["アクション", "アドベンチャー", "SF"],
  "release_date": "2019-04-26",
  "rating": 8.4,
  "director": "ルッソ兄弟",
  "studio": "マーベル・スタジオ",
  "location": {
    "lat": 40.7589,
    "lon": -73.9851
  }
}'

# 一括ドキュメント追加
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/json' -d'
{"index":{"_index":"movies","_id":"2"}}
{"title":"君の名は。","overview":"時空を超えた青春ラブストーリー","genre":["アニメ","ロマンス","ドラマ"],"release_date":"2016-08-26","rating":8.4,"director":"新海誠"}
{"index":{"_index":"movies","_id":"3"}}
{"title":"パラサイト 半地下の家族","overview":"格差社会を描いた韓国映画","genre":["スリラー","ドラマ","コメディ"],"release_date":"2019-05-30","rating":8.6,"director":"ポン・ジュノ"}
{"index":{"_index":"movies","_id":"4"}}
{"title":"トップガン マーヴェリック","overview":"トム・クルーズ主演の続編","genre":["アクション","ドラマ"],"release_date":"2022-05-27","rating":8.3,"director":"ジョセフ・コシンスキー"}
'

# ドキュメント更新
curl -X POST "localhost:9200/movies/_update/1" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "rating": 8.5,
    "updated_at": "2024-01-15"
  }
}'

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

検索クエリの実装

# 基本検索
curl -X GET "localhost:9200/movies/_search?q=アベンジャーズ"

# 構造化検索
curl -X GET "localhost:9200/movies/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "title": "アベンジャーズ"
    }
  },
  "size": 10,
  "from": 0
}'

# 複合検索(Bool Query)
curl -X GET "localhost:9200/movies/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        {"match": {"overview": "青春"}}
      ],
      "filter": [
        {"range": {"rating": {"gte": 8.0}}},
        {"term": {"genre": "ドラマ"}}
      ],
      "must_not": [
        {"term": {"genre": "ホラー"}}
      ],
      "should": [
        {"match": {"director": "新海誠"}}
      ]
    }
  },
  "sort": [
    {"rating": {"order": "desc"}},
    {"release_date": {"order": "desc"}}
  ]
}'

# ファセット検索(集約)
curl -X GET "localhost:9200/movies/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "genres": {
      "terms": {
        "field": "genre",
        "size": 10
      }
    },
    "avg_rating": {
      "avg": {
        "field": "rating"
      }
    },
    "rating_histogram": {
      "histogram": {
        "field": "rating",
        "interval": 1
      }
    },
    "release_years": {
      "date_histogram": {
        "field": "release_date",
        "calendar_interval": "year"
      }
    }
  }
}'

# 地理的検索
curl -X GET "localhost:9200/movies/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "10km",
          "location": {
            "lat": 40.7589,
            "lon": -73.9851
          }
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 40.7589,
          "lon": -73.9851
        },
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}'

ベクトル検索とAI機能

# k-NNベクトル検索の設定
curl -X PUT "localhost:9200/documents" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "index": {
      "knn": true,
      "knn.algo_param.ef_search": 100
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "content": {
        "type": "text"
      },
      "embedding": {
        "type": "knn_vector",
        "dimension": 768,
        "method": {
          "name": "hnsw",
          "space_type": "l2",
          "engine": "faiss",
          "parameters": {
            "ef_construction": 128,
            "m": 24
          }
        }
      }
    }
  }
}'

# ベクトルドキュメント追加
curl -X POST "localhost:9200/documents/_doc" -H 'Content-Type: application/json' -d'
{
  "title": "AI技術の進歩",
  "content": "人工知能技術は急速に発展しており、機械学習とディープラーニングが様々な分野で活用されています。",
  "embedding": [0.1, 0.2, 0.3, ...]
}'

# k-NN検索実行
curl -X GET "localhost:9200/documents/_search" -H 'Content-Type: application/json' -d'
{
  "size": 5,
  "query": {
    "knn": {
      "embedding": {
        "vector": [0.15, 0.25, 0.35, ...],
        "k": 10
      }
    }
  }
}'

# ハイブリッド検索(キーワード + ベクトル)
curl -X GET "localhost:9200/documents/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "hybrid": {
      "queries": [
        {
          "match": {
            "content": "人工知能"
          }
        },
        {
          "knn": {
            "embedding": {
              "vector": [0.15, 0.25, 0.35, ...],
              "k": 10
            }
          }
        }
      ]
    }
  }
}'

# ニューラル検索(意味的検索)
curl -X GET "localhost:9200/documents/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "neural": {
      "embedding": {
        "query_text": "機械学習アルゴリズム",
        "model_id": "huggingface_embeddings",
        "k": 10
      }
    }
  }
}'

高度な設定とパフォーマンス最適化

# クラスター設定
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
  "persistent": {
    "cluster.routing.allocation.disk.watermark.low": "85%",
    "cluster.routing.allocation.disk.watermark.high": "90%",
    "cluster.routing.allocation.disk.watermark.flood_stage": "95%",
    "cluster.max_shards_per_node": 3000,
    "search.max_buckets": 65536
  }
}'

# インデックステンプレート作成
curl -X PUT "localhost:9200/_index_template/logs_template" -H 'Content-Type: application/json' -d'
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 2,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs_policy",
      "index.lifecycle.rollover_alias": "logs"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "level": {
          "type": "keyword"
        },
        "message": {
          "type": "text",
          "analyzer": "standard"
        },
        "service": {
          "type": "keyword"
        },
        "host": {
          "type": "keyword"
        }
      }
    }
  }
}'

# Index State Management (ISM) ポリシー設定
curl -X PUT "localhost:9200/_plugins/_ism/policies/log_policy" -H 'Content-Type: application/json' -d'
{
  "policy": {
    "description": "Log retention policy",
    "default_state": "hot",
    "states": [
      {
        "name": "hot",
        "actions": [
          {
            "rollover": {
              "min_size": "5gb",
              "min_doc_count": 1000000,
              "min_index_age": "1d"
            }
          }
        ],
        "transitions": [
          {
            "state_name": "warm",
            "conditions": {
              "min_index_age": "7d"
            }
          }
        ]
      },
      {
        "name": "warm",
        "actions": [
          {
            "replica_count": {
              "number_of_replicas": 0
            }
          }
        ],
        "transitions": [
          {
            "state_name": "delete",
            "conditions": {
              "min_index_age": "30d"
            }
          }
        ]
      },
      {
        "name": "delete",
        "actions": [
          {
            "delete": {}
          }
        ]
      }
    ]
  }
}'

# パフォーマンス監視
curl -X GET "localhost:9200/_cluster/health?pretty"
curl -X GET "localhost:9200/_nodes/stats?pretty"
curl -X GET "localhost:9200/_cat/indices?v&s=store.size:desc"
curl -X GET "localhost:9200/_cat/shards?v&s=store:desc"

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

# セキュリティプラグイン設定(opensearch.yml)
cat >> config/opensearch.yml << 'EOF'
plugins.security.ssl.transport.pemcert_filepath: certs/opensearch.pem
plugins.security.ssl.transport.pemkey_filepath: certs/opensearch-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: certs/root-ca.pem
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: certs/opensearch.pem
plugins.security.ssl.http.pemkey_filepath: certs/opensearch-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: certs/root-ca.pem
plugins.security.allow_unsafe_democertificates: true
plugins.security.allow_default_init_securityindex: true
plugins.security.authcz.admin_dn:
  - CN=opensearch-admin,OU=IT,O=Example,L=Tokyo,ST=Tokyo,C=JP
plugins.security.nodes_dn:
  - CN=opensearch-node,OU=IT,O=Example,L=Tokyo,ST=Tokyo,C=JP
plugins.security.audit.type: internal_opensearch
plugins.security.enable_snapshot_restore_privilege: true
plugins.security.check_snapshot_restore_write_privileges: true
plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
plugins.security.system_indices.enabled: true
plugins.security.system_indices.indices:
  [
    ".opendistro-alerting-config",
    ".opendistro-alerting-alert*",
    ".opendistro-anomaly-results*",
    ".opendistro-anomaly-detector*",
    ".opendistro-anomaly-checkpoints",
    ".opendistro-anomaly-detection-state",
    ".opendistro-reports-*",
    ".opensearch-notifications-*",
    ".opensearch-notebooks",
    ".opensearch-observability",
    ".opendistro-asynchronous-search-response*",
    ".replication-metadata-store"
  ]
EOF

# ユーザー作成
curl -X PUT "https://localhost:9200/_plugins/_security/api/internalusers/analyst" \
  -u admin:admin -k -H 'Content-Type: application/json' -d'
{
  "password": "analyst@123",
  "opendistro_security_roles": ["readall"],
  "backend_roles": ["analytics_team"],
  "attributes": {
    "department": "analytics"
  }
}'

# ロール作成
curl -X PUT "https://localhost:9200/_plugins/_security/api/roles/movie_reader" \
  -u admin:admin -k -H 'Content-Type: application/json' -d'
{
  "cluster_permissions": ["cluster_monitor"],
  "index_permissions": [
    {
      "index_patterns": ["movies*"],
      "allowed_actions": ["read", "indices:data/read/*"]
    }
  ]
}'

# API Key作成
curl -X POST "https://localhost:9200/_plugins/_security/api/account" \
  -u admin:admin -k -H 'Content-Type: application/json' -d'
{
  "current_password": "admin",
  "password": "new_password_123"
}'

AWS統合とマネージドサービス

# AWS CloudFormation テンプレート(Amazon OpenSearch Service)
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  OpenSearchDomain:
    Type: AWS::OpenSearch::Domain
    Properties:
      DomainName: my-opensearch-domain
      EngineVersion: OpenSearch_2.11
      ClusterConfig:
        InstanceType: t3.medium.search
        InstanceCount: 3
        DedicatedMasterEnabled: true
        MasterInstanceType: t3.small.search
        MasterInstanceCount: 3
      EBSOptions:
        EBSEnabled: true
        VolumeType: gp3
        VolumeSize: 100
      VPCOptions:
        SecurityGroupIds:
          - !Ref OpenSearchSecurityGroup
        SubnetIds:
          - !Ref PrivateSubnet1
          - !Ref PrivateSubnet2
      EncryptionAtRestOptions:
        Enabled: true
      NodeToNodeEncryptionOptions:
        Enabled: true
      DomainEndpointOptions:
        EnforceHTTPS: true
      AccessPolicies:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
            Action: 'es:*'
            Resource: !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/my-opensearch-domain/*'

  OpenSearchSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for OpenSearch domain
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          SourceSecurityGroupId: !Ref ApplicationSecurityGroup
# Python boto3でのAWS OpenSearch Service操作
import boto3
from opensearchpy import OpenSearch, RequestsHttpConnection
from aws_requests_auth.aws_auth import AWSRequestsAuth

# AWS認証情報設定
session = boto3.Session()
credentials = session.get_credentials()
region = 'ap-northeast-1'
service = 'es'
host = 'search-my-domain-xxx.ap-northeast-1.es.amazonaws.com'

awsauth = AWSRequestsAuth(credentials, region, service)

# OpenSearchクライアント作成
client = OpenSearch(
    hosts=[{'host': host, 'port': 443}],
    http_auth=awsauth,
    use_ssl=True,
    verify_certs=True,
    connection_class=RequestsHttpConnection
)

# インデックス作成
response = client.indices.create(
    index='logs',
    body={
        'settings': {
            'number_of_shards': 2,
            'number_of_replicas': 1
        },
        'mappings': {
            'properties': {
                'timestamp': {'type': 'date'},
                'message': {'type': 'text'},
                'level': {'type': 'keyword'},
                'service': {'type': 'keyword'}
            }
        }
    }
)

# ドキュメント追加
response = client.index(
    index='logs',
    body={
        'timestamp': '2024-01-15T10:00:00',
        'message': 'Application started successfully',
        'level': 'INFO',
        'service': 'web-app'
    }
)

# 検索実行
response = client.search(
    index='logs',
    body={
        'query': {
            'bool': {
                'must': [
                    {'match': {'message': 'error'}}
                ],
                'filter': [
                    {'range': {'timestamp': {'gte': 'now-1d'}}}
                ]
            }
        },
        'sort': [
            {'timestamp': {'order': 'desc'}}
        ]
    }
)

print(f"Found {response['hits']['total']['value']} documents")

OpenSearchは、Elasticsearchのフォークから独自のアイデンティティを確立した現代的な検索・分析プラットフォームです。特にAWS環境での運用や、AI・ベクトル検索機能を活用した次世代アプリケーションの構築において、オープンソースの利点を活かしながら商用グレードの機能を提供する優れた選択肢です。