📖

OpenSearchのクラスター間検索を試してみる

2021/12/21に公開

この記事は、株式会社カオナビ Advent Calendar 2021の21日目の記事です。

はじめに

株式会社カオナビEMの@mettoboshiです。

全文検索システムを運用していると、以下のような悩みが発生することがあります。

  • とりあえずなんでも入れているため、インデックスが肥大化している
  • どんなデータが入っているか完全に把握している人はすでにいない
  • サービス側の変更を入れたいが、昔のデータがどうなっているか分からないし、全体を再インデックスするには無限に時間がかかる・・
  • もはや正しく検索できてないかもしれない。。。

サービスの仕様変更に耐えられるようにしておくためには、影響範囲をできるだけ小さくしておき、全容の把握を少しでもやりやすくしておくことが重要です。
全文検索システムにおいても、サービスごとはもちろん、例えば機能単位でドメインを別々にしておき、横断的に検索できるようにしておけば、もしかしたら部分的な変更ができるようになってよくある悩みが発生を抑制できるかもしれない?

というわけで今回は、Amazon OpenSearch Service(以下、OpenSearchとする)を使ってクラスター間検索を試してみました。

今回試したことは、公式ドキュメントの「Amazon OpenSearch Service のクラスター間検索」にもあるので、1次情報を確認したい方はそちらも合わせて参考にしてみてください。

クラスター間検索を行うための前提条件や制限事項

OpenSearchでクラスター間検索を行うためには、以下の前提条件や制限事項があるので注意が必要です。

  • OpenSearchまたはElasticsearch6.7以降
  • きめ細かなアクセスコントロールが有効
  • ノード間暗号化が有効
  • M3インスタンスとT2インスタンスではないこと。
  • クラスター間検索できるドメインの数は20個まで。

他にもいくつか制限事項はあるので、気になる方はLimitationsを参照してください。

構成

今回は、検索元のドメイン1つ(cross-cluster-search-src)と、検索先のドメイン2つ(cross-cluster-search-dst1, cross-cluster-search-dst2)を用意し、srcに対して検索リクエストを送り、dst1, dst2のドメインへの検索をできるようにしてみます。

準備

環境やデータの準備をしていきます。
まずはドメインの作成から。

ドメインの作成

今回は検証用環境なので、ドメイン作成を参考に以下の設定でドメインを作成しました。

グループ 項目 設定値
名前 ドメイン名 cross-cluster-search-src(※1)
デプロイタイプ Deployment type 開発およびテスト
バージョン 1.0
データノード インスタンスタイプ t3.small.search
ネットワーク ネットワーク パブリックアクセス(※2)
きめ細かなアクセスコントロール きめ細かなアクセスコントロールを有効化 ON
マスターユーザー マスターユーザーの作成
マスターユーザー名 任意
マスターパスワード 任意
アクセスポリシー ドメインアクセスポリシー きめ細かなアクセスコントロールのみを使用(※3)

※1 ドメイン名は任意。今回は、cross-cluster-search-src, cross-cluster-search-dst1, cross-cluster-search-dst2の3つを設定
※2 今回は一時的な検証用なのでパブリックアクセスにしています
※3 接続先のドメインには、アクセスポリシーの追加をします(後述)が、ここで設定しても構いません。

ドメインアクセスポリシーの変更

dst1, dst2はsrc側から接続を許可する必要があるので、es:ESCrossClusterGetを許可する必要があります。
ドメインレベルのアクセスポリシーの設定で以下のように編集しておきましょう。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "*"
        ]
      },
      "Action": [
        "es:*"
      ],
      "Resource": "arn:aws:es:[region]:[account]:domain/cross-cluster-search-dst1/*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:ESCrossClusterGet",
      "Resource": "arn:aws:es:[region]:[account]:domain/cross-cluster-search-dst1"
    }
  ]
}

dst1やdst2の設定を開くと、regionやaccountがわかるので、同じものを使って、es:ESCrossClusterGetの許可を追加しておきます。

接続リクエストの追加

クラスター間の検索をできるようにするために、srcからdst1,2への接続を許可しておきます。

src→dst1への接続リクエスト

ドメインの画面の接続タブから、接続のリクエストや承認ができます。


src側からリクエストを行いdst1, dst2でリクエストを承認する流れになります。
「リクエスト」ボタンを押下時の入力項目は以下のように設定しました。

項目 設定値
接続エイリアス dst1(※)
送信先クラスター この AWS アカウントのクラスターに接続する
ドメイン cross-cluster-search-dst1

※ 接続エイリアスは、実際の検索を実行する時にも使用するので、わかりやすい名前にしておきましょう。

dst1側でリクエストを承認

ドメイン>接続>インバウンド接続から対象のリモートドメインを選択し、「承認」ボタンを押下します。

同じことをdst2にも行いsrc→dst2の接続もできるようにしておきます。

データの準備

各ドメインにデータを入れていきます。

dst1にデータを入れる

今回はpostmanを使ってデータを入れていきます。
今回は、チュートリアルにあるsample-movie.zipを使いました。

解凍した、サンプルデータをdst1に入れていきます。
以下のAPIを使用します。

https://[dst1-domain-endpoint]/_bulk

postmanの画面的にはこんな感じ。


実際の設定値は以下のイメージです。

タブ 項目 設定値 備考
Authorization Type Basic Auth Username, Passwordはドメイン作成時に設定したもの(※)
Headers KEY ContentType
VALUE application/json
Body binaly sample-movie.bulk 執筆時に使ったデータでは、最終行に改行コードがありデータの登録に失敗したので、一部データを削除して使いました。

※以降使うAPIも基本的にAuthorizationにBasic Authの値を入れて実行します。

dst2にデータを入れる

dst1には_bulkでデータを入れてみたので、dst2はkibanaのサンプルデータを追加してみます。

dst2のドメインからOpenSearch DashboardsのURLを開き、Home/Add dataからサンプルデータを追加します。

画面から「Add data」ボタンを押下するだけで簡単にサンプルデータが入ります。
追加したデータのインデックスは以下のAPIで確認することが可能です。

https://[dst2-domain-endpoint]/_cat/indices

上記APIを実行すると、サンプルデータには、「opensearch_dashboards_sample_data_ecommerce」
というインデックスがあることが確認できました。

動作確認

準備が整ったので、クラスター間の検索ができるか確認してみます。

srcからdst1のデータを検索する

src側のドメインに対して接続で指定した、エイリアスとインデックスを指定することで、dst1にあるインデックスが検索可能になります。

dst1:moviesを指定して_searchを行ってみます。

https://[src-domain-endpoint]/dst1:movies/_search

結果はこんな感じです。dst1に対して検索を行った時と同じ結果が出ました。
件数は4999件。

{
    "took": 194,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "_clusters": {
        "total": 1,
        "successful": 1,
        "skipped": 0
    },
    "hits": {
        "total": {
            "value": 4999,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "dst1:movies",
                "_type": "movie",
                "_id": "tt2226417",
                "_score": 1.0,
                "_source": {
                    "directors": [
                        "James Wan"
                    ],
                    "release_date": "2013-09-13T00:00:00Z",
                    "rating": 7.1,
                    "genres": [
                        "Horror",
                        "Thriller"
                    ],
                    "image_url": "https://m.media-amazon.com/images/M/MV5BMTg0OTA5ODIxNF5BMl5BanBnXkFtZTcwNTUzNDg4OQ@@._V1_SX400_.jpg",
                    "plot": "The haunted Lambert family seeks to uncover the mysterious childhood secret that has left them dangerously connected to the spirit world.",
                    "title": "Insidious: Chapter 2",
                    "rank": 7,
                    "running_time_secs": 6360,
                    "actors": [
                        "Patrick Wilson",
                        "Rose Byrne",
                        "Barbara Hershey"
                    ],
                    "year": 2013,
                    "id": "tt2226417",
                    "type": "add"
                }
            },
以下省略

srcからdst2のデータを検索する

同じやり方で、dst2も検索してみます。

https://[src-domain-endpoint]/dst2:opensearch_dashboards_sample_data_ecommerce/_search

結果は、以下のような感じでした。
件数は4675件。

{
    "took": 82,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "_clusters": {
        "total": 1,
        "successful": 1,
        "skipped": 0
    },
    "hits": {
        "total": {
            "value": 4675,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "dst2:opensearch_dashboards_sample_data_ecommerce",
                "_type": "_doc",
                "_id": "q0rN0n0BPuJ5oxxrbsNT",
                "_score": 1.0,
                "_source": {
                    "category": [
                        "Men's Clothing"
                    ],
                    "currency": "EUR",
                    "customer_first_name": "Eddie",
                    "customer_full_name": "Eddie Underwood",
                    "customer_gender": "MALE",
                    "customer_id": 38,
                    "customer_last_name": "Underwood",
                    "customer_phone": "",
                    "day_of_week": "Monday",
                    "day_of_week_i": 0,
                    "email": "eddie@underwood-family.zzz",
                    "manufacturer": [
                        "Elitelligence",
                        "Oceanavigations"
                    ],
                    "order_date": "2022-01-03T09:28:48+00:00",
                    "order_id": 584677,
                    "products": [
                        {
                            "base_price": 11.99,
                            "discount_percentage": 0,
                            "quantity": 1,
                            "manufacturer": "Elitelligence",
                            "tax_amount": 0,
                            "product_id": 6283,
                            "category": "Men's Clothing",
                            "sku": "ZO0549605496",
                            "taxless_price": 11.99,
                            "unit_discount_amount": 0,
                            "min_price": 6.35,
                            "_id": "sold_product_584677_6283",
                            "discount_amount": 0,
                            "created_on": "2016-12-26T09:28:48+00:00",
                            "product_name": "Basic T-shirt - dark blue/white",
                            "price": 11.99,
                            "taxful_price": 11.99,
                            "base_unit_price": 11.99
                        },
                        {
                            "base_price": 24.99,
                            "discount_percentage": 0,
                            "quantity": 1,
                            "manufacturer": "Oceanavigations",
                            "tax_amount": 0,
                            "product_id": 19400,
                            "category": "Men's Clothing",
                            "sku": "ZO0299602996",
                            "taxless_price": 24.99,
                            "unit_discount_amount": 0,
                            "min_price": 11.75,
                            "_id": "sold_product_584677_19400",
                            "discount_amount": 0,
                            "created_on": "2016-12-26T09:28:48+00:00",
                            "product_name": "Sweatshirt - grey multicolor",
                            "price": 24.99,
                            "taxful_price": 24.99,
                            "base_unit_price": 24.99
                        }
                    ],
                    "sku": [
                        "ZO0549605496",
                        "ZO0299602996"
                    ],
                    "taxful_total_price": 36.98,
                    "taxless_total_price": 36.98,
                    "total_quantity": 2,
                    "total_unique_products": 2,
                    "type": "order",
                    "user": "eddie",
                    "geoip": {
                        "country_iso_code": "EG",
                        "location": {
                            "lon": 31.3,
                            "lat": 30.1
                        },
                        "region_name": "Cairo Governorate",
                        "continent_name": "Africa",
                        "city_name": "Cairo"
                    },
                    "event": {
                        "dataset": "sample_ecommerce"
                    }
                }
            },
以下省略

srcからdst1とdst2のデータを検索する

最後にdst1,dst2を一緒に検索してみます。
インデックスの指定の部分をカンマ区切りで追加することで、2つのドメイン・インデックスを同時に検索可能です。
今回はdst1:movies,dst2:opensearch_dashboards_sample_data_ecommerceと指定します。

https://[src-domain-endpoint]/dst1:movies,dst2:opensearch_dashboards_sample_data_ecommerce/_search

結果は以下のような感じに。
件数は9674件。
dst1は4999件, dst2は4675件だったので2インデックス分の検索がHitしてそうに見えます。

{
    "took": 64,
    "timed_out": false,
    "num_reduce_phases": 3,
    "_shards": {
        "total": 6,
        "successful": 6,
        "skipped": 0,
        "failed": 0
    },
    "_clusters": {
        "total": 2,
        "successful": 2,
        "skipped": 0
    },
    "hits": {
        "total": {
            "value": 9674,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "dst1:movies",
                "_type": "movie",
                "_id": "tt2226417",
                "_score": 1.0,
                "_source": {
                    "directors": [
                        "James Wan"
                    ],
                    "release_date": "2013-09-13T00:00:00Z",
                    "rating": 7.1,
                    "genres": [
                        "Horror",
                        "Thriller"
                    ],
                    "image_url": "https://m.media-amazon.com/images/M/MV5BMTg0OTA5ODIxNF5BMl5BanBnXkFtZTcwNTUzNDg4OQ@@._V1_SX400_.jpg",
                    "plot": "The haunted Lambert family seeks to uncover the mysterious childhood secret that has left them dangerously connected to the spirit world.",
                    "title": "Insidious: Chapter 2",
                    "rank": 7,
                    "running_time_secs": 6360,
                    "actors": [
                        "Patrick Wilson",
                        "Rose Byrne",
                        "Barbara Hershey"
                    ],
                    "year": 2013,
                    "id": "tt2226417",
                    "type": "add"
                }
            },
            {
                "_index": "dst1:movies",
                "_type": "movie",
                "_id": "tt2109248",
                "_score": 1.0,
                "_source": {
                    "directors": [
                        "Michael Bay"
                    ],
                    "release_date": "2014-06-25T00:00:00Z",
                    "genres": [
                        "Action",
                        "Adventure",
                        "Sci-Fi"
                    ],
                    "image_url": "https://m.media-amazon.com/images/M/MV5BMTQyMDA5Nzg0Nl5BMl5BanBnXkFtZTgwNzA4NDcxMDE@._V1_SX400_.jpg",
                    "plot": "A mechanic and his daughter make a discovery that brings down Autobots and Decepticons - and a paranoid government official - on them.",
                    "title": "Transformers: Age of Extinction",
                    "rank": 10,
                    "year": 2014,
                    "actors": [
                        "Mark Wahlberg",
                        "Nicola Peltz",
                        "Jack Reynor"
                    ],
                    "id": "tt2109248",
                    "type": "add"
                }
            },
以下省略

他にも以下のような検索もちゃんと動作していました。

  • パラメータを指定した検索
https://[src-domain-endpoint]/dst1:movies,dst2:opensearch_dashboards_sample_data_ecommerce/_search?q=Elitelligence

requestbodyでクエリを指定する検索も動作しました。

  • sizeの指定
{
  "query": {
    "match_all": {}
  },
  "size": 1
}

  • moviesにもopensearch_dashboards_sample_data_ecommerceにも存在する項目の検索
{
  "query": {
    "match": {
      "type": {
        "query": "add"
      }
    }
  }
}
  • movieになくて、opensearch_dashboards_sample_data_ecommerceに存在する項目のquery検索
{
  "query": {
    "match": {
      "customer_last_name": {
        "query": "Bailey"
      }
    }
  }
}

無事、別のドメインを指定して検索ができることが確認できました。

あとしまつ

OpenSearchはインスタンスの停止が(おそらく)できないので、遊んだ後は削除する必要があります。
しかし、今回のようにクラスター間の接続をしている場合、ドメインを削除しようとするとエラーが発生します。

そのため、まずはdst1,dst2の接続タブから、インバウンド接続を削除したのちドメインを削除しておきましょう。

まとめ

今回は、OpenSearchのクラスター間検索を試してみました。
複数ドメインをまたいだ検索を行えるようにしておくことで、各ドメインに持たせるインデックスの範囲を小さくすることや、データの持ち方の変更することができる可能性を感じました。また、ドメインを別にすることで、ドメイン単位でスケールさせることも可能になるので、データ量に応じてシステム構成を変えることもできそうです。

実運用をすることを考えるとまだまだ検討事項はありますが、それはおいおい考えていくことにして。今回はひとまずここまでにしておきます。

最後まで読んでいただきありがとうございました。
明日の記事もお楽しみに!

Discussion