🔎

OpenSearch Sererlessへの移行を検討する時に注意したいこと

2022/12/11に公開

こんにちは!

最近AWSからOpenSearch ServerlessのPreview版が発表されて、
本業で運用しているAWS OpenSearch Serviceを将来的にOpenSearch Serverlessへ移行したいなと思い色々と調査を行っています。

これまでに自分で調査出来た内容として備忘録的にまとめます。

Serverlssで稼働するOpenSearchのバージョンは2.3

Serverless collections currently run OpenSearch version 2.3.

https://docs.aws.amazon.com/opensearch-service/latest/developerguide/serverless-overview.html#:~:text=Serverless collections currently run OpenSearch version 2.3

公式より↑とのことなので、現行で運用しているOpenSearch Serviceから移行を検討する場合は、
先に2.3へアップグレードした上で試すのが良いかと思います。

また、OpenSearch Serviceで2.3へアップグレードするためには、
1.3経由で無いと出来ないようなので注意が必要です。

https://dev.classmethod.jp/articles/upgrade-amazon-opensearch-service-1x-to-23/

従って、現行で1.0や1.1、1.2を利用している場合は以下の手順で2.3へアップグレードすることになります。

現行 => 1.3 => 2.3

慎重に移行するならばindexingだけでも同時稼働させて徐々に検索も稼働させる

公式のclientがmultiホストに対応しているので、
同時稼働させた状態で最初は↓のようにindexingだけでも事前に本番稼働や負荷テストをやりつつ、
後から徐々にServerlessでの検索へ移行していくのが良いかと思っています。

  • OpenSearch
    • 検索: 利用する
    • indexing: する
  • OpenSearch Serverless
    • 検索: 利用しない
    • indexing: する

delete_by_queryやupdate_by_queryが対応していない

https://dev.classmethod.jp/articles/opensearch-serverless-limitation/#:~:text=クエリを用いて登録済みのドキュメントを一括で更新/削除するAPIですが、OpenSearch Serverlessに上記のAPIは含まれていません。

個人的には一番衝撃的でした。
まだGA版になっていないので何とも言えないですが、
今のところは既存の実装を修正しないといけなそうです。

修正方法についての具体例

投稿を格納するpostというindexがあったとして、
以下のような設計になっていたとします。

field_name field_type
_id ドキュメントID
id integer
title text
content text
user_id integer

例として、任意のユーザに紐づく投稿を全て削除したい場合は以下のような処理を実装するかと思います。
※ opensearch-jsを利用した場合の例です。

client.deleteByQuery({
  index: "post",
  body: {
    query: {
      bool: {
        should: [
          {term: {user_id: userId}}
        ],
      },
    },
  },
});

これをdelete_by_query APIを使わずに実装しようとするとひと手間かかることになります。
以下はドキュメントID一覧をOpenSearchから取得した上でBulk APIから投稿を削除するサンプルです。

// 削除対象のドキュメントID一覧をscroll api経由で取得する
const scroll = client.helpers.scrollSearch({
  index: 'post',
  size: 100,
  scroll: '1m',
  body: {
    query: {
      bool: {
        should: [
          {term: {user_id: userId}}
        ],
      },
    },
    _source: ['_id'],
  },
});

const ids = [];
for await (const response of scroll) {
  response.body.hits.hits.forEach((hit) => {
    ids.push(hit._source._id);
  });
}

// bulk apiで該当のドキュメントIDをまとめて削除
client.helpers.bulk({
  datasource: ids.map(_id => ({
    delete: {
      index: "post",
      _id
    }
  })).flat(),
  onDocument(doc) {
    return doc;
  }
});

update_by_queryを利用している場合も同様に更新対象のドキュメントID一覧を取得した後にBulk APIで更新リクエストをすることになると思います。

検索可能になるまでのラグによって発生しうる処理漏れについて

The refresh interval for indexes might be between 10 and 30 seconds depending on the size of your requests.

https://docs.aws.amazon.com/opensearch-service/latest/developerguide/serverless-overview.html#:~:text=The refresh interval for indexes might be between 10 and 30 seconds depending on the size of your requests

あとは、indexの更新間隔が10秒〜30秒になる場合があるとのことなので、
この記事の例でいくと、

  • ユーザが投稿を行った後、瞬時に任意のユーザに紐づく投稿を全て削除

というリクエストが発生した場合は、消し漏れが発生する可能性があるんじゃないかと思いました。
更新処理についても同様にです。
(更新・削除対象のドキュメントID一覧をOpenSearchから検索して取得した上でBulk API等で処理する場合のことです。

この懸念点についてはしっかり調査を行った上で移行を見極める必要がありそうです。

まとめ

細かい違いについては公式ドキュメントclassmethod社の記事を参照することでキャッチアップ出来るかと思います。

indexing後の検索可能になるまでのラグについては一番の懸念点でもあるので、
GA版になるタイミングである程度解消されれば良いなと思っております。

引き続きOpenSearch Serverlessのキャッチアップを行っていきます。

Discussion