【ハンズオン】Dockerで簡単!OpenSearchの環境構築と使い方


【ハンズオン】Dockerで簡単!OpenSearchの環境構築と使い方

はじめに

近年、大量のデータを高速に検索・分析・可視化する必要性が高まっています。ECサイトの商品検索、アプリケーションのログ監視、セキュリティインシデントの分析など、その活用範囲は多岐にわたります。このようなニーズに応える強力なツールとして注目されているのが、オープンソースの検索・分析エンジン「OpenSearch」です。

OpenSearchとは?

OpenSearchは、Amazon Web Services (AWS)が主導して開発しているコミュニティドリブンのオープンソースプロジェクトです。元々はElasticsearch 7.10.2からフォーク(分岐)して誕生しました。そのため、Elasticsearchが持つ強力な全文検索、スケーラビリティ、リアルタイム分析といった特徴を引き継ぎつつ、Apache License, Version 2.0のもとで誰でも自由に利用・変更・配布ができる真のオープンソースとして開発が進められています。

OpenSearchは、検索エンジン本体である「OpenSearch」と、データを可視化・分析するためのダッシュボードツール「OpenSearch Dashboards」の2つの主要コンポーネントで構成されています。

なぜDockerを使うのか?

OpenSearchのような分散システムをローカル環境に構築するのは、Javaのバージョン管理、設定ファイルの編集、複数プロセスの起動など、手間がかかる作業です。しかし、「Docker」を使えば、これらの複雑な手順を数個のコマンドで完結させることができます。

Dockerは、アプリケーションを「コンテナ」と呼ばれる隔離された環境で実行するためのプラットフォームです。Dockerを使うことで、以下のようなメリットがあります。

  • 環境構築の簡便さ: docker-compose.ymlという設定ファイル一つで、OpenSearchとOpenSearch Dashboardsを同時に起動できます。
  • 環境の再現性: 誰が実行しても同じ環境を構築できるため、「自分のマシンでは動かない」といった問題を回避できます。
  • クリーンな環境: ホストOSを汚すことなく、不要になったらコンテナと関連データを簡単に削除できます。

この記事で学べること

この記事は、Dockerを使ってOpenSearchの環境を手軽に構築し、その基本的な使い方をマスターすることを目的としたハンズオン形式のガイドです。具体的には、以下の内容をステップバイステップで学んでいきます。

  1. 環境構築: Docker Composeを使い、OpenSearchとOpenSearch Dashboardsを起動します。
  2. データの投入: サンプルの映画データをOpenSearchに投入(インデックス)します。
  3. データの検索: OpenSearchの強力な検索機能(Query DSL)を使って、様々な条件でデータを検索します。
  4. データの可視化: OpenSearch Dashboardsを使い、投入したデータをグラフなどで可視化し、インタラクティブなダッシュボードを作成します。

対象読者

  • Web開発者、バックエンドエンジニア
  • インフラエンジニア、SRE
  • データアナリスト、データサイエンティスト
  • Dockerの基本的なコマンド(docker pull, docker runなど)を理解している方
  • 検索技術やデータ分析基盤に興味がある方

さあ、準備はよろしいでしょうか? Dockerを使ってOpenSearchの世界へ飛び込みましょう!


準備編:必要なツールをインストールしよう

ハンズオンを始める前に、お使いのコンピュータに必要なツールをインストールします。必要なのは「Docker」だけです。(Gitは任意ですが、あると便利です)

Docker Desktopのインストール

Dockerは、Windows, macOS, Linuxの各OSで利用できます。Docker Desktopをインストールすることで、Docker Engineだけでなく、複数のコンテナを管理するためのdocker composeコマンドも一緒にインストールされます。

お使いのOSに合わせて、公式サイトからDocker Desktopをダウンロードし、インストールしてください。

インストールが完了したら、ターミナル(Windowsの場合はPowerShellまたはコマンドプロンプト)を開き、以下のコマンドを実行してバージョン情報が表示されることを確認してください。

“`bash

Dockerのバージョン確認

docker –version

Docker Composeのバージョン確認 (v2の場合)

docker compose version

または (v1の場合)

docker-compose –version

“`

出力例:
Docker version 25.0.3, build 4debf41
Docker Compose version v2.24.6-desktop.1

バージョン番号は異なっていても問題ありません。コマンドがエラーにならずに実行できればOKです。

Gitのインストール (任意)

この記事では、設定ファイルやサンプルデータを手動で作成しますが、Gitがインストールされていると、リポジトリをクローンするだけで準備が完了するため便利です。もしインストールしていない場合は、公式サイトからダウンロードしてインストールすることをおすすめします。

インストール後、以下のコマンドでバージョンを確認できます。

bash
git --version

出力例:
git version 2.39.3 (Apple Git-145)

これで準備は完了です。次の章から、いよいよOpenSearch環境の構築に入ります。


構築編:Docker ComposeでOpenSearch環境を立ち上げよう

ここでは、docker-compose.ymlという1つの設定ファイルを使って、OpenSearchとOpenSearch Dashboardsからなる環境を構築します。

ステップ1: プロジェクトディレクトリの作成

まず、作業用のディレクトリを作成し、その中に移動します。ターミナルで以下のコマンドを実行してください。

“`bash

作業用ディレクトリを作成

mkdir opensearch-handson

作成したディレクトリに移動

cd opensearch-handson
“`

今後の作業は、すべてこの opensearch-handson ディレクトリ内で行います。

ステップ2: docker-compose.yml の作成

次に、テキストエディタ(VS Code, Sublime Text, Vimなど)を使って、opensearch-handson ディレクトリ内に docker-compose.yml という名前のファイルを作成し、以下の内容をコピー&ペーストしてください。

docker-compose.yml
“`yaml
version: ‘3.8’

services:
# OpenSearch本体のサービス定義
opensearch-node1:
image: opensearchproject/opensearch:2.11.1 # バージョンを明示的に指定
container_name: opensearch-node1
environment:
– cluster.name=opensearch-cluster
– node.name=opensearch-node1
– discovery.type=single-node
– bootstrap.memory_lock=true # メモリスワップを無効化しパフォーマンス向上
– “OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m” # JVMヒープサイズ。開発用に小さく設定
– “DISABLE_SECURITY_PLUGIN=true” # ハンズオン用にセキュリティ機能を無効化
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
– opensearch-data1:/usr/share/opensearch/data # データを永続化
ports:
– “9200:9200” # OpenSearch APIポート
– “9600:9600” # パフォーマンス分析用ポート
networks:
– opensearch-net

# OpenSearch Dashboardsのサービス定義
opensearch-dashboards:
image: opensearchproject/opensearch-dashboards:2.11.1 # OpenSearchとバージョンを合わせる
container_name: opensearch-dashboards
ports:
– “5601:5601” # DashboardsのUIポート
expose:
– “5601”
environment:
– ‘OPENSEARCH_HOSTS=[“http://opensearch-node1:9200”]’ # 接続先のOpenSearchを指定
– “DISABLE_SECURITY_DASHBOARDS_PLUGIN=true” # セキュリティ無効化に伴う設定
depends_on:
– opensearch-node1 # opensearch-node1が起動してから起動する
networks:
– opensearch-net

volumes:
opensearch-data1:

networks:
opensearch-net:
“`

docker-compose.yml の詳細解説

このファイルに何が書かれているのか、詳しく見ていきましょう。

  • version: '3.8': Docker Composeファイルのフォーマットバージョンを指定しています。
  • services: 起動するコンテナ(サービス)の集まりを定義します。今回はopensearch-node1opensearch-dashboardsの2つです。
  • opensearch-node1サービス:
    • image: 使用するDockerイメージを指定します。opensearchproject/opensearchが公式イメージです。:2.11.1のようにバージョンを明記することで、意図しないバージョンアップを防ぎ、再現性を高めます。
    • container_name: コンテナに付ける名前です。
    • environment: コンテナ内で使用する環境変数を設定します。
      • discovery.type=single-node: 今回は1台のノードでクラスタを構成するため、この設定が必要です。
      • bootstrap.memory_lock=true: パフォーマンス向上のため、JVMが使用するメモリが物理メモリにロックされ、スワップアウトされるのを防ぎます。
      • OPENSEARCH_JAVA_OPTS: OpenSearchが動作するJava仮想マシン(JVM)のヒープサイズを指定します。開発環境ではリソースを節約するため、512MBに設定しています。本番環境ではより大きな値を設定する必要があります。
      • DISABLE_SECURITY_PLUGIN=true: 非常に重要です。 これにより、OpenSearchのセキュリティ機能(認証・認可など)が無効になります。ハンズオンを簡単にするための設定であり、本番環境では絶対にfalseにしてください。
    • ulimits: コンテナのリソース制限を設定します。memlockbootstrap.memory_lock=trueを有効にするために必要です。
    • volumes: データを永続化するための設定です。opensearch-data1:/usr/share/opensearch/dataは、コンテナ内のデータディレクトリをDockerの管理するボリューム(opensearch-data1)にマウントします。これにより、コンテナを停止・削除してもデータが消えません。
    • ports: ホストOSとコンテナのポートを紐付けます。9200:9200により、ホストOSの9200番ポートへのアクセスがコンテナの9200番ポートに転送されます。9200はOpenSearchのAPIが待ち受けるデフォルトポートです。
    • networks: コンテナが接続するネットワークを指定します。
  • opensearch-dashboardsサービス:
    • image: OpenSearch Dashboardsの公式イメージです。OpenSearch本体とバージョンを合わせることが推奨されます。
    • ports: 5601:5601は、DashboardsのWeb UIにアクセスするためのポートです。
    • environment:
      • OPENSEARCH_HOSTS: Dashboardsが接続するOpenSearchのエンドポイントを指定します。コンテナ名(opensearch-node1)で通信できるのは、同じDockerネットワーク(opensearch-net)に接続しているためです。
      • DISABLE_SECURITY_DASHBOARDS_PLUGIN=true: OpenSearch本体のセキュリティ機能を無効化したことに伴い、Dashboards側のプラグインも無効にします。
    • depends_on: opensearch-node1が起動してからこのサービスが起動するように依存関係を定義します。
  • volumes / networks (トップレベル): services内で使用する名前付きボリュームとカスタムネットワークを定義しています。

ステップ3: コンテナの起動

docker-compose.ymlが保存できたら、ターミナルで以下のコマンドを実行してコンテナを起動します。

bash
docker compose up -d

  • up: docker-compose.ymlに基づいてコンテナを作成し、起動します。
  • -d: デタッチドモード(バックグラウンド)で実行します。これを付けないと、ログがターミナルに流れ続け、Ctrl+Cで停止するとコンテナも停止してしまいます。

初回の実行では、Dockerイメージのダウンロードが行われるため、少し時間がかかります。

ステップ4: 動作確認

コンテナが正常に起動したか確認しましょう。

  1. コンテナの状態確認
    docker compose psコマンドを実行します。

    bash
    docker compose ps

    以下のように、opensearch-node1opensearch-dashboardsSTATUSrunning(またはhealthy)になっていれば成功です。

    NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
    opensearch-dashboards opensearchproject/opensearch-dashboards:2.11.1 "/usr/share/opensea…" opensearch-dashboards 2 minutes ago running (healthy) 0.0.0.0:5601->5601/tcp, :::5601->5601/tcp
    opensearch-node1 opensearchproject/opensearch:2.11.1 "/usr/local/bin/doc…" opensearch-node1 2 minutes ago running (healthy) 0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9600->9600/tcp, :::9600->9600/tcp

  2. OpenSearch APIの動作確認
    curlコマンドを使って、OpenSearchのAPIエンドポイント(ポート9200)にリクエストを送ってみます。

    bash
    curl http://localhost:9200

    以下のようなJSONが返ってくれば、OpenSearchが正常に動作しています。

    json
    {
    "name" : "opensearch-node1",
    "cluster_name" : "opensearch-cluster",
    "cluster_uuid" : "xxxxxxxxxxxxxxxxxxxxxx",
    "version" : {
    "distribution" : "opensearch",
    "number" : "2.11.1",
    "build_type" : "tar",
    "build_hash" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "build_date" : "2023-11-14T22:22:42.239339736Z",
    "build_snapshot" : false,
    "lucene_version" : "9.7.0",
    "minimum_wire_compatibility_version" : "7.10.0",
    "minimum_index_compatibility_version" : "7.0.0"
    },
    "tagline" : "The OpenSearch Project: https://opensearch.org/"
    }

  3. OpenSearch Dashboardsの動作確認
    Webブラウザを開き、アドレスバーに http://localhost:5601 と入力してください。
    以下のようなOpenSearch Dashboardsのホーム画面が表示されれば成功です。

OpenSearch Dashboards Welcome Screen

(バージョンによって多少デザインが異なる場合があります)

これで、あなたのローカルマシンにOpenSearchの分析基盤が整いました!


実践編①:データの投入 (Indexing)

環境ができたので、次は実際にデータを投入してみましょう。OpenSearchにデータを保存する行為を「インデックスする (Indexing)」と呼びます。

OpenSearchの基本概念

ここで、OpenSearchを扱う上で重要な基本概念をいくつか押さえておきましょう。

  • Index (インデックス): 関連するドキュメントの集まりです。リレーショナルデータベース(RDB)の「テーブル」に似た概念です。例えば、「商品データ」を格納するproductsインデックスや、「ブログ記事」を格納するarticlesインデックスなどを作成します。
  • Document (ドキュメント): インデックスに格納されるデータの1単位で、JSON形式で表現されます。RDBの「行(レコード)」に相当します。各ドキュメントは一意なIDを持ちます。
  • Mapping (マッピング): インデックス内のドキュメントが持つフィールドのデータ型(テキスト、数値、日付など)を定義するスキーマです。RDBのテーブル定義に似ています。マッピングを明示的に定義することもできますが、定義せずにドキュメントを投入すると、OpenSearchが自動的に型を推測してマッピングを作成してくれます(Dynamic Mapping)。

ハンズオン用のサンプルデータ準備

今回は、架空の映画データをサンプルとして使用します。opensearch-handsonディレクトリ内に、movies.jsonというファイルを作成し、以下の内容を貼り付けてください。

このデータは、OpenSearchのBulk APIという、複数の操作(この場合はドキュメントの作成)を一度のリクエストで効率的に行うための特殊なフォーマットになっています。奇数行が操作内容(どのインデックスに、どのIDで作成するか)、偶数行がドキュメント本体です。

movies.json
json
{"index": {"_index": "movies", "_id": "1"}}
{"title": "The Shawshank Redemption", "year": 1994, "genre": ["Drama"], "director": "Frank Darabont", "rating": 9.3}
{"index": {"_index": "movies", "_id": "2"}}
{"title": "The Godfather", "year": 1972, "genre": ["Crime", "Drama"], "director": "Francis Ford Coppola", "rating": 9.2}
{"index": {"_index": "movies", "_id": "3"}}
{"title": "The Dark Knight", "year": 2008, "genre": ["Action", "Crime", "Drama"], "director": "Christopher Nolan", "rating": 9.0}
{"index": {"_index": "movies", "_id": "4"}}
{"title": "Pulp Fiction", "year": 1994, "genre": ["Crime", "Drama"], "director": "Quentin Tarantino", "rating": 8.9}
{"index": {"_index": "movies", "_id": "5"}}
{"title": "Forrest Gump", "year": 1994, "genre": ["Drama", "Romance"], "director": "Robert Zemeckis", "rating": 8.8}
{"index": {"_index": "movies", "_id": "6"}}
{"title": "Inception", "year": 2010, "genre": ["Action", "Adventure", "Sci-Fi"], "director": "Christopher Nolan", "rating": 8.8}
{"index": {"_index": "movies", "_id": "7"}}
{"title": "The Matrix", "year": 1999, "genre": ["Action", "Sci-Fi"], "director": "Lana Wachowski", "rating": 8.7}
{"index": {"_index": "movies", "_id": "8"}}
{"title": "Spirited Away", "year": 2001, "genre": ["Animation", "Adventure", "Family"], "director": "Hayao Miyazaki", "rating": 8.6}
{"index": {"_index": "movies", "_id": "9"}}
{"title": "Parasite", "year": 2019, "genre": ["Comedy", "Drama", "Thriller"], "director": "Bong Joon Ho", "rating": 8.5}
{"index": {"_index": "movies", "_id": "10"}}
{"title": "The Lord of the Rings: The Return of the King", "year": 2003, "genre": ["Action", "Adventure", "Drama"], "director": "Peter Jackson", "rating": 9.0}

データの投入方法

データの投入には、主に2つの方法があります。

方法1: cURLを使ったBulk APIでの投入

ターミナルからcurlコマンドを使って、作成したmovies.jsonファイルをBulk APIに送信します。opensearch-handsonディレクトリで以下のコマンドを実行してください。

bash
curl -XPOST "http://localhost:9200/_bulk?pretty" -H "Content-Type: application/json" --data-binary "@movies.json"

  • -XPOST: HTTPメソッドにPOSTを指定します。
  • "http://localhost:9200/_bulk?pretty": Bulk APIのエンドポイントです。?prettyを付けると、レスポンスのJSONがきれいに整形されて見やすくなります。
  • -H "Content-Type: application/json": 送信するデータがJSON形式であることを示すヘッダーです。
  • --data-binary "@movies.json": ファイルの内容をリクエストボディとして送信します。@をファイル名の前に付けるのがポイントです。

成功すると、以下のようなレスポンスが返ってきます。"errors": falseとなっていれば、すべてのデータが問題なく投入されたことを示します。

json
{
"took" : 100, // 処理にかかった時間(ミリ秒)
"errors" : false, // エラーがなかったか
"items" : [
{
"index" : {
"_index" : "movies",
"_id" : "1",
"_version" : 1,
"result" : "created", // 作成された
"payload" : null,
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201 // HTTPステータスコード
}
},
// ... (他のドキュメントの結果が続く) ...
]
}

方法2: OpenSearch DashboardsのDev Toolsを使った投入

curlに慣れていない場合は、GUIからAPIを直接実行できる「Dev Tools」が便利です。

  1. ブラウザでOpenSearch Dashboards (http://localhost:5601) を開きます。
  2. 左側のナビゲーションメニューから、ハンバーガーアイコン(三本線)をクリックし、ManagementセクションにあるDev Toolsを選択します。
  3. 左側のエディタ画面に、APIリクエストを記述します。movies.jsonの中身をすべてコピーし、エディタに貼り付けてください。ただし、先頭にPOST /_bulkという行を追加します。

    POST /_bulk
    {"index": {"_index": "movies", "_id": "1"}}
    {"title": "The Shawshank Redemption", "year": 1994, "genre": ["Drama"], "director": "Frank Darabont", "rating": 9.3}
    {"index": {"_index": "movies", "_id": "2"}}
    {"title": "The Godfather", "year": 1972, "genre": ["Crime", "Drama"], "director": "Francis Ford Coppola", "rating": 9.2}
    ... (以下略) ...

  4. 緑色の再生ボタン(▶)をクリックするか、Ctrl + Enter (Macの場合は Cmd + Enter) を押してリクエストを実行します。

  5. 右側の画面に、curlで実行したときと同じ結果が表示されます。

Dev Toolsは、この後の検索の章でも頻繁に使う非常に便利なツールです。

投入したデータの確認

データが正しく投入されたか、いくつかAPIを叩いて確認してみましょう。Dev Toolsで実行するのが簡単です。

  1. インデックスのドキュメント数を数える
    _count APIを使うと、指定したインデックスのドキュメント数を取得できます。

    GET /movies/_count
    実行結果:
    json
    {
    "count" : 10,
    "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
    }
    }

    "count": 10と表示され、10件のドキュメントが正しく存在することがわかります。

  2. 特定のドキュメントを取得する
    IDを指定して、特定のドキュメントを取得してみましょう。ID 1の映画を取得します。

    GET /movies/_doc/1
    実行結果:
    json
    {
    "_index" : "movies",
    "_id" : "1",
    "_version" : 1,
    "_seq_no" : 0,
    "_primary_term" : 1,
    "found" : true,
    "_source" : {
    "title" : "The Shawshank Redemption",
    "year" : 1994,
    "genre" : [
    "Drama"
    ],
    "director" : "Frank Darabont",
    "rating" : 9.3
    }
    }

    "found": trueとなり、_sourceの中にドキュメントの内容が格納されていることが確認できました。

これでデータの投入は完了です。いよいよOpenSearchの真骨頂である検索機能を使ってみましょう。


実践編②:データの検索 (Searching)

OpenSearchの最も強力な機能は、その柔軟で高速な検索能力です。検索にはQuery DSL (Domain Specific Language) と呼ばれるJSONベースの言語を使用します。SQLに似ていますが、より表現力豊かで、全文検索や地理空間検索、スコアリングの制御など、複雑な検索を直感的に記述できます。

この章では、Dev Toolsを使って様々な検索クエリを実行してみます。

検索の基本: _search API

検索は、インデックス名の後ろに _search を付けたエンドポイントに対して行います。

全件検索 (match_all)

まずは最もシンプルな、すべてのドキュメントを検索するクエリです。

GET /movies/_search
{
"query": {
"match_all": {}
}
}

"query"の中に、どのような条件で検索するかを記述します。match_allは「すべてのドキュメントにマッチする」という意味です。
実行すると、hitsというキーの中に検索結果が配列で返されます。デフォルトでは10件までしか返されません。

json
{
// ... (took, timed_outなど)
"hits" : {
"total" : {
"value" : 10,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "movies",
"_id" : "1",
"_score" : 1.0, // 検索条件との関連度スコア
"_source" : { ... } // ドキュメント本体
},
// ... (他のヒットしたドキュメントが続く)
]
}
}

キーワード検索 (match)

特定のフィールドに対して、キーワードを含むドキュメントを検索します。これは最も一般的に使われる全文検索クエリです。
titleフィールドに “dark knight” という単語が含まれる映画を検索してみましょう。

GET /movies/_search
{
"query": {
"match": {
"title": "dark knight"
}
}
}

このクエリは、titleフィールドの値をアナライザに通した結果と検索キーワードを比較します。”The Dark Knight” というタイトルは、アナライザによって “the”, “dark”, “knight” のようなトークン(単語)に分割されます。検索キーワード “dark knight” も同様に “dark”, “knight” に分割され、いずれかのトークンにマッチするドキュメントが検索対象となります。大文字・小文字は区別されません。

結果として、ID 3 の “The Dark Knight” がヒットするはずです。

フレーズ検索 (match_phrase)

単語の順序も考慮して検索したい場合は match_phrase を使います。
titleに “Lord of the Rings” というフレーズが含まれる映画を探します。

GET /movies/_search
{
"query": {
"match_phrase": {
"title": "Lord of the Rings"
}
}
}

これにより、ID 10 の “The Lord of the Rings: The Return of the King” がヒットします。もし match クエリで “Rings of Lord” と検索してもヒットする可能性がありますが、match_phrase では語順が違うためヒットしません。

完全一致検索 (term)

アナライザによる分割を行わず、キーワードとフィールドの値が完全に一致するドキュメントを検索するには term クエリを使います。これは主に、keyword 型や数値、真偽値など、分割する必要のないフィールドの検索に用います。

例えば、ジャンルが Action の映画を検索してみましょう。

GET /movies/_search
{
"query": {
"term": {
"genre": "Action"
}
}
}

これを実行すると、期待通りにヒットしないか、意図しない結果になるはずです。なぜでしょうか?

これは、Dynamic Mappingによって genre フィールドが text 型としてマッピングされ、アナライザによって “Action” が “action” という小文字のトークンに変換されているためです。一方、term クエリは入力された “Action” をそのまま検索しようとするため、マッチしません。

このようなケースに対応するため、OpenSearchは多くの場合、text 型のフィールドに対して .keyword というサブフィールドを自動的に作成します。この .keyword フィールドは keyword 型であり、アナライザを通さず、値をそのままの文字列として扱います。

正しいクエリは以下のようになります。

GET /movies/_search
{
"query": {
"term": {
"genre.keyword": "Action"
}
}
}

これで、genre 配列に “Action” を含む映画が正しく検索されます。

複合条件検索 (bool)

複数の条件を組み合わせて検索するには bool クエリを使います。SQLの AND, OR, NOT に相当する句を持っています。

  • must: すべての条件を満たす必要がある (AND)
  • should: いずれかの条件を満たせばよい (OR)
  • must_not: この条件を満たしてはならない (NOT)
  • filter: mustと同じくAND条件ですが、スコアリングを計算しません。そのため、単純な絞り込みに使うと高速です。

例: ジャンルが “Drama” で、かつ公開年が2000年以降の映画を検索

ここでは、ジャンルのマッチングはスコアに影響させ、年代の絞り込みはスコア計算不要のフィルタリングとします。

GET /movies/_search
{
"query": {
"bool": {
"must": [
{ "match": { "genre": "Drama" } }
],
"filter": [
{
"range": {
"year": {
"gte": 2000 // gte = Greater than or equal to (以上)
}
}
}
]
}
}
}

range クエリは数値や日付の範囲を指定するのに使います。gte (以上), gt (より大きい), lte (以下), lt (より小さい) が指定できます。

このクエリを実行すると、”The Dark Knight” (2008), “Inception” (2010), “Spirited Away” (2001, ただしDramaではないのでヒットしない), “Parasite” (2019), “The Lord of the Rings…” (2003) の中から、ジャンルに “Drama” を含むものがヒットします。

検索結果のカスタマイズ

検索結果の表示を調整することもできます。

  • sizefrom: ページネーションを実現します。sizeで取得件数、fromで開始位置を指定します。
  • _source: 返却するフィールドを限定します。titleyearだけが欲しい場合は以下のようにします。
  • sort: 結果をソートします。rating(評価)で降順にソートしてみましょう。

これらを組み合わせたクエリの例です。

GET /movies/_search
{
"size": 5,
"from": 0,
"_source": ["title", "year", "rating"],
"query": {
"match_all": {}
},
"sort": [
{
"rating": {
"order": "desc" // desc = descending (降順)
}
}
]
}

このクエリは、全映画を評価の高い順にソートし、最初の5件のタイトル、公開年、評価だけを表示します。

Query DSLは非常に奥が深いですが、ここで紹介した match, term, bool, range を使いこなすだけでも、かなり高度な検索が実現できます。


実践編③:データの可視化 (Visualization)

OpenSearchのもう一つの強力な機能が、OpenSearch Dashboardsによるデータの可視化です。投入したデータを元に、様々なグラフを作成し、それらを組み合わせたインタラクティブなダッシュボードを簡単に構築できます。

ステップ1: Index Patternの作成

Dashboardsでデータを扱うには、まず「どのインデックスのデータを可視化の対象にするか」を定義する Index Pattern を作成する必要があります。

  1. OpenSearch Dashboards (http://localhost:5601) を開きます。
  2. 左のナビゲーションメニューからハンバーガーアイコン(三本線)をクリックし、Management -> Stack Management を選択します。
  3. 左側のメニューから Index Patterns をクリックします。
  4. Create index pattern ボタンをクリックします。
  5. Step 1 of 2: Define index pattern
    • Index pattern name の入力欄に movies と入力します。moviesインデックスにマッチするパターンとして認識されます。
    • 入力欄の下に “Success! Your index pattern matches 1 source.” と表示されることを確認します。
    • Next step をクリックします。
  6. Step 2 of 2: Configure settings
    • Time field(時間フィールド)を選択する画面になりますが、今回のデータにはメインとなる時系列フィールドがないため、ドロップダウンから I don't want to use a time filter を選択します。
    • Create index pattern ボタンをクリックします。

これで movies Index Patternが作成され、フィールドの一覧(title, year, genreなど)が表示されます。

ステップ2: データの探索 (Discover)

可視化を作成する前に、Discover 機能でデータがどのように見られるか確認してみましょう。

  1. 左のナビゲーションメニューの最上部にあるハンバーガーアイコンをクリックし、OpenSearch Plugins -> Discover を選択します。
  2. 左上でIndex Patternが movies になっていることを確認します。
  3. 画面中央に、投入した映画データが時系列(今回はなし)とテーブル形式で表示されます。各ドキュメントの左にある > をクリックすると、JSON形式で詳細を確認できます。
  4. 上部の検索バーに director:Nolan と入力してEnterキーを押すと、監督が”Nolan”の映画(実際にはアナライザにより”nolan”にマッチする映画)だけがフィルタリングされます。このようにKQL(Kibana Query Language)というシンプルな構文で簡単にフィルタリングできます。

ステップ3: 可視化の作成 (Visualize Library)

いよいよグラフを作成します。ここでは2つの例を作成します。

  1. ジャンルごとの映画本数(パイチャート)
  2. 年代ごとの映画本数(棒グラフ)
可視化の作成フロー
  1. 左のナビゲーションメニューから OpenSearch Plugins -> Visualize Library を選択します。
  2. Create visualization ボタンをクリックします。
  3. 作成したいグラフの種類を選択する画面が表示されます。
例1: パイチャート (ジャンル別)
  1. グラフの種類から Pie を選択します。
  2. データソースとして、先ほど作成した movies を選択します。
  3. 右側の Data パネルでグラフの設定を行います。
    • Metrics: パイチャートの各部分の大きさを何で決めるか。デフォルトの Count のままでOKです(ドキュメント数を数える)。
    • Buckets: データをどのようにグループ化するか。
      • Add をクリックし、Split slices を選択します。(スライスを分割する)
      • Aggregation(集計方法)で Terms を選択します。(フィールドの値ごとにグループ化)
      • Field(対象フィールド)で genre.keyword を選択します。(.keyword を使うのがポイント)
      • Size10 などに設定し、表示するジャンル数を調整します。
  4. 設定が完了したら、パネル下部の Update ボタンをクリックします。
  5. 画面中央に、ジャンルごとの映画本数を示すパイチャートが表示されます。DramaやActionが多いことが一目でわかります。
  6. 画面上部の Save ボタンをクリックし、Genre Distribution などの名前を付けて保存します。
例2: 垂直棒グラフ (年代別)
  1. 再び Visualize Library に戻り、Create visualization をクリックします。
  2. グラフの種類から Vertical Bar を選択し、データソースとして movies を選択します。
  3. 右側の Data パネルで設定します。
    • Metrics: Y-axis(Y軸)は Count のままでOKです。
    • Buckets:
      • Add をクリックし、X-axis を選択します。(X軸を定義する)
      • AggregationHistogram を選択します。(数値範囲でグループ化)
      • Fieldyear を選択します。
      • Interval(間隔)に 10 と入力します。これにより、10年区切り(1970-1979, 1980-1989…)で集計されます。
  4. Update ボタンをクリックすると、年代ごとの映画本数を示す棒グラフが表示されます。
  5. Save ボタンをクリックし、Movies by Decade などの名前で保存します。

ステップ4: ダッシュボードの作成

最後に、作成した2つのビジュアライゼーションを1つの画面にまとめて、ダッシュボードを作成します。

  1. 左のナビゲーションメニューから OpenSearch Plugins -> Dashboard を選択します。
  2. Create dashboard ボタンをクリックします。
  3. 画面左上の Add をクリックします。
  4. Add panels という画面が表示され、保存したビジュアライゼーションの一覧が出てきます。
  5. Genre DistributionMovies by Decade の両方をクリックして選択します。選択するとリストから消え、ダッシュボードに追加されます。
  6. Add panels 画面を右上の x で閉じます。
  7. ダッシュボード上に2つのグラフが配置されています。それぞれのパネルの右下をドラッグしてサイズを変更したり、パネル自体をドラッグ&ドロップして位置を自由に変更できます。
  8. インタラクティブ機能の確認:
    • パイチャートの Drama の部分をクリックしてみてください。
    • ダッシュボードにフィルタ(genre.keyword: Drama)が適用され、右側の棒グラフが「Dramaジャンルを含む映画の年代別分布」に動的に変化します。
    • これがDashboardsの強力なインタラクティブ機能です。
  9. 画面上部の Save ボタンをクリックし、Movie Analysis Dashboard などの名前でダッシュボードを保存します。

お疲れ様でした! これであなたは、DockerでOpenSearch環境を立ち上げ、データを投入・検索し、その結果を可視化するまでの一連の流れをマスターしました。


発展編:セキュリティ機能を有効にする

今回のハンズオンでは、簡単にするためにOpenSearchのセキュリティ機能を無効化しました。しかし、本番環境や複数人で利用する環境では、セキュリティ機能は必須です。

ここでは、セキュリティ機能を有効にするための手順の概要を説明します。

  1. docker-compose.yml の変更
    docker-compose.ymlenvironment セクションを以下のように変更します。

    “`yaml

    opensearch-node1のenvironment

    environment:
    – cluster.name=opensearch-cluster
    – node.name=opensearch-node1
    – discovery.type=single-node
    – bootstrap.memory_lock=true
    – “OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m”
    – “DISABLE_SECURITY_PLUGIN=false” # “true”から”false”へ変更
    – “OPENSEARCH_INITIAL_ADMIN_PASSWORD=YourStrongPassword!” # 管理者パスワードを設定

    opensearch-dashboardsのenvironment

    environment:
    – ‘OPENSEARCH_HOSTS=[“https://opensearch-node1:9200”]’ # “http”から”https”へ変更
    – “DISABLE_SECURITY_DASHBOARDS_PLUGIN=false” # “true”から”false”へ変更
    # Dashboardsはデフォルトでadmin/YourStrongPassword! を使って接続を試みる
    ``
    * セキュリティプラグインを有効 (
    false) にします。
    *
    OPENSEARCH_INITIAL_ADMIN_PASSWORDで初期管理者(admin)ユーザーのパスワードを設定します。**必ず強力なパスワードに変更してください。**
    * Dashboardsの接続先を
    https` に変更します。セキュリティを有効にすると、通信はTLS/SSLで暗号化されます。

  2. コンテナの再起動
    変更を保存し、コンテナを再起動します。

    bash
    docker compose down # 一旦停止
    docker compose up -d # 再度起動

    初回起動時には、TLS証明書の生成などが行われるため、起動に通常より時間がかかります。

  3. 動作確認

    • curl でアクセスする場合:
      bash
      # -k は自己署名証明書のエラーを無視するオプション
      # -u でユーザー名とパスワードを指定
      curl -k -u admin:YourStrongPassword! https://localhost:9200
    • Dashboards (http://localhost:5601) にアクセスすると、ログイン画面が表示されます。ユーザー名に admin、パスワードに設定したものを入力してログインします。

セキュリティ機能には、ユーザー・ロール管理、きめ細かいアクセス制御(インデックス単位、ドキュメント単位、フィールド単位)、監査ログなど、豊富な機能が含まれています。本番運用に向けて、ぜひ公式ドキュメントを参考に設定を進めてみてください。


クリーンアップ

ハンズオンが終わり、作成した環境が不要になった場合は、以下のコマンドでコンテナ、ネットワーク、そしてデータが保存されていたボリュームをすべて綺麗に削除できます。

opensearch-handson ディレクトリで以下のコマンドを実行してください。

bash
docker compose down -v

  • down: upで作成したコンテナやネットワークを停止・削除します。
  • -v: docker-compose.ymlで定義された名前付きボリュームも一緒に削除します。これを付けないと、opensearch-data1ボリュームが残り続け、ディスク容量を消費するので注意してください。

このコマンド一つで、ハンズオン開始前のクリーンな状態に戻すことができます。これもDockerの大きな利点です。


まとめ

この記事では、Docker Composeを利用してOpenSearchとOpenSearch Dashboardsの環境を構築し、データの投入、検索、可視化という一連の基本的な操作をハンズオン形式で学びました。

  • Dockerによる簡単な環境構築: docker-compose.ymlファイル一つで、複雑な分散システムの環境を数分で立ち上げられる手軽さを体験しました。
  • データの投入と検索: Bulk APIによる効率的なデータ投入と、Query DSLを使った柔軟で強力な検索を実践しました。match, term, bool などの基本的なクエリは、今後のOpenSearch活用において基礎となります。
  • データの可視化: OpenSearch Dashboardsを使い、プログラミングなしで直感的にデータを可視化し、インタラクティブなダッシュボードを作成できることを学びました。

OpenSearchは、ここで紹介した機能以外にも、多くの可能性を秘めています。

  • プラグインの活用: 日本語を適切に扱うための形態素解析プラグイン(kuromoji)の導入。
  • ログ分析基盤: FluentdやLogstashと連携し、アプリケーションやサーバーのログをリアルタイムで収集・分析する基盤の構築。
  • クラスタ構成: 複数のノードでクラスタを組み、耐障害性とスケーラビリティを高める。

今回のハンズオンが、皆様にとってOpenSearchの世界への第一歩となれば幸いです。ぜひ、ご自身のプロジェクトや興味のあるデータで、その強力な機能を試してみてください。

参考資料

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール