ベクトル検索対応に向けたWEAR検索インデクサー刷新 ── OpenSearch Ingestionでの試行錯誤

ベクトル検索対応に向けたWEAR検索インデクサー刷新 ── OpenSearch Ingestionでの試行錯誤

はじめに

こんにちは。WEARバックエンド部SREブロックの春日です。普段はWEARというサービスのSREとして開発・運用に携わっています。

本記事では、WEARのハイブリッド検索のリリースに伴い刷新した検索インデクシングシステム(以下、インデクサー)について、OpenSearch Ingestionを採用しようとした際にハマったポイントや、ベクトル検索のためのインデクサーを設計する上で工夫した点を中心に紹介します。

目次

背景

WEARでは、検索基盤としてAmazon OpenSearch Service(以下、OpenSearch)を利用しています1。これまでフリーワード検索ではタグマッチングを主軸としていましたが、タグが付与されていない検索ワードに対する検索結果の質と量に課題がありました。 これを改善するため、ベクトル検索と全文検索を組み合わせたハイブリッド検索(WEARではあいまい検索と呼んでいるため、以下「あいまい検索」と表記)をリリースすることになりました2

あいまい検索のためにベクトル検索を導入するには、検索対象の各documentに対して、タイトル・説明文・タグなどを連結したテキストをベクトル化したフィールドを持たせる必要があります。しかしながら、既存のインデクサーでこのフローを実現するのは難しく、インデクサー自体を刷新することになりました。本記事ではその刷新の過程と、設計時に行った工夫を紹介します。

既存のインデクサーと刷新の動機

WEARではOpenSearchへのインデクシングをEmbulkを用いて行っていました。 embulk-input-bigqueryembulk-output-elasticsearchなどを組み合わせ、BigQueryからOpenSearchへデータを連携する構成です。EmbulkのジョブはDigdagのworkflowで管理し、Amazon EKS(以下、EKS)上のJobとして実行していました3。インデクサーには差分更新と日次更新の2種類があり、それぞれ次の役割を持っていました。

  • 差分更新:10分間隔で実行。直近で新規投稿・更新documentをインデクシングし、削除された投稿をindexから削除
  • 日次更新:1日1回、新しいindexを作成して全件をインデクシングし、Blue/Greenでエイリアスを切り替える形で全件更新する。統計データなどの日次で更新すべき値はこのタイミングで反映

しかし、ベクトル検索の導入を検討するにあたり、この構成にはいくつかの課題がありました。

  • WEARで一番大きいコーディネートのindexは大量のdocumentを持っており、これらを毎日ベクトル化するのはコストと処理時間の両面で非現実的
  • BigQueryからOpenSearchへの連携中にベクトル化の処理を挟むのが困難
  • 本対応の検討時点でEmbulkはすでにメンテナンスがされていない状態であり、長期的な保守性に不安

これらを踏まえ、ベクトル検索対応に必要な機能と、長期的な保守性の両方を満たす構成へとインデクサーを刷新する方針を決めました。

ベクトルデータの保持方法の検討

最初に取り組んだのが、ベクトルデータをどこに、どのタイミングで持たせるかという検討です。

既存の日次更新では新しいindexを毎日作成して全件インデクシングしていましたが、大量のデータを毎日全件ベクトル化するのは非現実的なため、ベクトルデータを別ストレージに保存しておく案を検討しました。しかし、ベクトル取得時のパフォーマンスやコスト面で見合わないと判断し、最終的には日次での全件更新そのものを廃止する方針を取りました。

毎日indexを全件更新するメリットの1つとして、indexの不整合が発生した場合に、日次での全件更新によって整合性を保つことができるという点がありました。これは例として、差分更新の失敗時のリトライで、古いデータで新しいデータが上書きされてしまうといった状況が挙げられます。全件更新を廃止するにあたり、この点をどう担保するのかが課題でしたが、後述する方法でdocumentのバージョニングを行うことで、不整合が発生しないようにしました。

新しい設計では、ベクトル化は差分更新のみで行い、日次更新では同じindexに対して日次で更新すべき値のみを上書きするように責務を分けました。これにより、ベクトル化を投稿の追加・更新時のみに限定でき、ベクトル化コストと処理時間の問題を回避できるようになりました。

インデクサーの構成方針

インデクサー刷新にあたって、ベクトル化を含む新しい構成として複数の選択肢を検討しましたが、OpenSearch Ingestionを軸とする構成を採用しました。判断のポイントは以下の通りです。

  • 自前で運用する外部ツールは最小限にしたい(Embulkのように追加でメンテナンスが必要なツールを増やしたくない)
  • データ抽出のSQLはバックエンドエンジニア、インデクサーのインフラ構築・運用はSREという責務分離を維持し、両者を疎結合にしたい
  • AWS公式のLambdaプロセッサでベクトル化するパターンを参考にすれば、ベクトル化部分をLambdaへ切り出して柔軟に構成できそう

これらを総合的に考慮し、Amazon S3(以下、S3)を起点としたAWS Lambda(以下、Lambda)の構成を方針として進めることになりました。

BigQuery → S3 のデータ連携

WEARではMicrosoft SQL ServerからBigQueryへリアルタイム連携をしており、インデクサー側もBigQueryからデータを取得しています。前述の通り、インデクサーはS3を起点としてデータを処理する設計を取っているため、BigQueryから取得したデータをS3に連携する必要があります。BigQueryから直接S3へ出力する機能はないため、いったんCloud Storage(以下、GCS)へ出力してからS3へ転送する形を取りました。

GCSへの出力にはBigQueryのEXPORT DATAを利用しています。差分更新・日次更新いずれもJSON Lines形式でGCSへ出力するように記述しており、以下に差分更新を例にしたものを記載します。

EXPORT DATA
  OPTIONS(
    uri='gs://GCS_BUCKET/coordinates/diff/raw-data/YYYY/MM/DD/HH/mm/data_*.jsonl',
    format='JSON',
    overwrite=true
  ) AS
-- 対象データを取得するクエリ
  ...

uriにワイルドカード(*)を含めることで、BigQueryが出力サイズに応じて自動的に複数ファイルへ分割します。出力フォーマットはJSONを指定するとJSON Lines形式になります。

GCSからS3への転送方法は、差分更新と日次更新で異なるツールを使い分けています。

DataSyncは大量データの高速転送に適していますが、タスクの起動・実行に約5分かかります。差分更新は10分間隔で実行する上、ベクトル化のような時間のかかる処理も挟まるため、起動に時間のかかるDataSyncは許容できませんでした。差分更新ではデータ量がそこまで多くないこともあり、rcloneを採用しています。

日次更新の設計

日次更新では、もともとEmbulkで実装されていた全件更新を廃止し、差分更新と同じindexに対して統計データなどの日次で更新すべき値のみを上書きする方式に変更しました。日次更新の構成は以下の通りです。

日次更新の構成図

日次更新はOpenSearch Ingestionを採用しており、S3に格納された全件データに対してS3 scanでOpenSearchへbulkでupsertしています。OpenSearch Ingestionのパイプライン定義の例は以下のとおりです。

version: 2
coordinates-daily-indexer:
  source:
    s3:
      acknowledgments: true
      delete_s3_objects_on_read: true
      scan:
        buckets:
        - bucket:
            name: ${BUCKET_NAME}
            filter:
              include_prefix: ["coordinates/daily/raw-data/"]
      aws:
        region: ap-northeast-1
        sts_role_arn: ${STS_ROLE_ARN}
      codec:
        ndjson: {}
  processor:
  - delete_entries:
      with_keys:
      - s3
  sink:
  - opensearch:
      hosts:
      - https://${OPENSEARCH_HOST}
      aws:
        region: ap-northeast-1
        sts_role_arn: ${STS_ROLE_ARN}
      index_type: custom
      index: coordinates
      document_id: ${/id}
      action: upsert
      max_retries: 10
      bulk_size: 5
      dlq:
        s3:
          bucket: ${BUCKET_NAME}
          key_path_prefix: "dlq/coordinates/daily/"
          region: ap-northeast-1
          sts_role_arn: ${STS_ROLE_ARN}

source.s3.scanでS3バケット内の対象プレフィックスをスキャンします。 processor.delete_entriesでS3イベントメタデータを落とし、sink.opensearch でOpenSearchへbulk upsertしています。失敗したdocumentはdlq.s3で指定したS3パスへ退避されます。

刷新前は4〜6時間ほど動き続けていた日次更新のジョブが、刷新後は1時間以内で完了するようになりました。これは更新フィールドを必要なものに絞れたことも要因の1つですが、OpenSearch Ingestionの処理が速いことも大きな要因です。

差分更新の設計

日次更新のような、すでにS3に格納されているデータをスキャンしてまとめて投入するユースケースでは、OpenSearch Ingestionは安定して動作することが分かっていました。ただし、S3 scanでS3データを処理するのはOpenSearch Ingestion起動のタイミングのみで、起動後にS3へ投入されたデータは処理されません。

日次更新の場合は実行のたびにOpenSearch Ingestionを起動し、完了したら終了させることで意図した動作が行えます。しかし、OpenSearch Ingestionの起動・終了にはそれぞれ5分ほどかかるため、10分ごとに実行される差分更新ではその実行時間は許容できません。

そのため差分更新では起動済みのOpenSearch IngestionにAmazon Simple Queue Service(以下、SQS)経由でデータを連携することにしました。これは、OpenSearch Ingestionのパイプラインを起動したまま、SQS経由でリアルタイムに少量ずつデータを取り込む構成です。

初期設計:OpenSearch Ingestion+Lambdaプロセッサでのベクトル化とインデクシング

差分更新の初期構成は以下の通りです。しかし、この構成ではいくつかの課題が発生し、最終的には断念しました。

差分更新の構成図v1

OpenSearch IngestionにはLambdaプロセッサがあり、パイプラインの途中でLambdaを呼び出して任意の処理を実行できます。これを使ってAmazon Bedrock(以下、Bedrock)でのベクトル化を行う想定でした。

1万件の差分更新で表面化した問題

この構成で約1万件規模の差分更新を試したところ、いくつかの問題に直面しました。

  • OpenSearch IngestionのLambdaプロセッサは同期実行のみで、OpenSearch IngestionからLambdaへのread timeoutも10秒固定で調整できない
  • 短時間に大量のベクトル化を行うとBedrockのリクエスト数クォータ超過でThrottlingExceptionが発生し、Lambda内でリトライしてもread timeoutする
  • LambdaプロセッサがエラーになってもOpenSearch Ingestion側からリトライを設定する手段がない
  • Lambdaプロセッサで処理が失敗したメッセージはOpenSearch IngestionのDead Letter Queue(以下、DLQ)には送られない。さらにS3の元ファイルも削除される仕様のため、失敗データが完全に消えてしまう。原因追跡やリカバリーができず、運用に耐えない
  • パイプライン側からLambdaへの流量制限ができず、Bedrockを呼ぶLambdaへ過剰なリクエストが流れてしまう
  • スロットリングを抑える目的でOCUとsource.s3.sqs.maximum_messagesを1にしても、Lambdaへの接続時にコネクションプール枯渇エラーが発生。S3に投入した1万件のうちOpenSearchに格納されたのは約6,900件で、残り3,100件ほどが毎回OpenSearch IngestionのDLQに溜まってしまう

ここまでの検証から、OpenSearch IngestionのLambdaプロセッサは今回のユースケースには適さないと判断しました。

Lambdaプロセッサを諦めてベクトル化処理をOpenSearch Ingestionの外で行うことにします。後段のOpenSearch IngestionはS3に置かれたベクトル化済みデータを読んでSQS経由でリアルタイムに投入する構成とすれば、ここまでに挙げた問題は回避できそうだと考えました。

再設計:ベクトル化Lambdaを前段に出す

OpenSearch IngestionからLambdaプロセッサを外し、ベクトル化を前段のLambdaに切り出した再設計を検証しました。しかし、この構成でも問題が発生しました。

差分更新の構成図v2

ベクトル化部分をLambdaに切り出したことで、リトライ・流量制御をLambda側で完結できるようになり、初期設計で発生していた問題は解消されました。1万件規模の差分更新ではこの構成で安定して動作することを確認できました。

しかし、データ量を増やして検証を進めると、後段のSQS → OpenSearch Ingestion → OpenSearchの経路で別の問題が表面化しました。

  • 3万件〜10万件規模になると、投入自体は完了しているにもかかわらず、OpenSearch IngestionがSQSメッセージを掴んだまま処理を継続し続け、可視性タイムアウトが切れて再処理が走る
  • OpenSearch側でcircuit breakerが頻発し、upsert自体は成功しているにもかかわらずSQSメッセージが消費されず、同様に可視性タイムアウト切れで再処理が走る
  • SQS → OpenSearch Ingestionの経路で流量制限ができないため、上記の挙動を緩和する手段がない

普段の差分更新で扱うデータ量が常に1万件以下に収まるなら見送りもできましたが、障害やメンテナンス明けに溜まったデータを一度に流すケースを考えると、大量データで挙動が崩れる構成は採用できません。

今回のユースケースだとOpenSearch Ingestionでは運用に耐えないと判断し、OpenSearch投入部分もLambdaに置き換える方針としました。

最終設計:S3+SQS+Lambdaで非同期にベクトル化とインデクシング

再設計で残っていたOpenSearch Ingestion部分も自作のLambdaに置き換え、S3とSQSを挟んで非同期に処理を進める構成にしました。最終的に、この構成で安定して処理できるようになりました。

差分更新の構成図v3

ベクトル化を担うLambdaと、OpenSearchへ投入するLambdaを分け、それぞれS3のオブジェクト作成イベントをSQS経由で受け取って動作させます。この構成にすることで、次のような恩恵が得られました。

  • ベクトル化でBedrockのクォータを超過した場合、SQSが自動的にリトライする
  • Lambdaの同時実行数を設定することで、BedrockとOpenSearchへの流量を独立に制御できる
  • ベクトル化処理が重くなっても、後段のOpenSearch投入には影響が及ばない

この構成に切り替えた後、10万件規模の差分更新でも想定時間内に推論からupsertまで完了することを確認でき、再設計で発生していたSQS再処理やcircuit breakerの問題も解消されました。実運用の定常時は1万件以下、最大でも数万件規模ですが、障害やメンテナンス明けに大量データを一度に流すケースでも問題なく捌けるようになっています。

ベクトル化Lambdaでの工夫

ベクトル化LambdaはS3に格納されたファイルをSQS経由で受け取り、1ファイルずつ処理します。次のような点を工夫しました。

Bedrockのリージョン分散

ベクトル化に利用しているamazon.titan-embed-text-v2:0モデルは、リージョンごとに1分あたり6,000回のクォータがあり、これは調整不可でした4。WEARではOpenSearchのコネクタ経由でも検索時の検索ワードのベクトル化を行っており、こちらはap-northeast-1リージョンを利用しています。インデクサーのベクトル化がap-northeast-1のクォータを使い切ってしまうと、検索時のベクトル化に影響が出てしまいます。

そのため、ベクトル化Lambdaでは検索とは別のリージョンを使うようにしました。具体的にはus-east-1us-west-2の2つを使い、リクエストごとに順序をシャッフルして順に試行する形にしています。これにより、検索側のクォータに影響を与えず、かつLambda側で利用できるクォータも実質的に2倍に増やせています。

クォータ超過(ThrottlingException)の場合は別リージョンへフォールバックし、すべて埋まっていたら指数バックオフでリトライするようにしました。

1ファイル単位の処理量を制御する

ベクトル化Lambdaは1ファイル1実行で動作するため、1ファイル内のデータ量が多すぎるとBedrock呼び出しに時間がかかり、Lambdaのタイムアウトに引っかかる問題が発生しました。Lambdaのタイムアウトはリトライまでの時間とBedrockクォータエラー時の挙動を考慮して60秒に設定しています。

最初はBigQueryのEXPORT DATA時点でファイルサイズを制限する方法を検討しました。公式ドキュメントのエクスポートファイルのサイズを制限するに従い、対象データをパーティション分割した上でEXPORT DATAをループ処理する方式です。しかし、この方式はBigQuery側の並列ワーカーで一括出力する場合と比べて出力時間が大幅に伸びてしまい、差分更新の実行間隔である10分には到底収まらないため断念しました。

最終的には、GCSからS3へ転送する段階で1ファイルあたり500KBを上限として分割し、1ファイル内のデータ量を一定以下に抑えました。シェルスクリプトとして以下のような処理を組み込んでいます。

# GCS から S3 へのストリーミング転送例
# 第1引数: SRC(例: gcs:bucket/prefix/), 第2引数: DST(例: s3:bucket/prefix/)
SRC="$1"; DST="$2"
CHUNK_BYTES="500K"
JOBS=4

# 1) しきい値以下のファイルはそのまま move
rclone move "$SRC" "$DST" \
  --max-size "$CHUNK_BYTES" --min-size 1B --include "*.jsonl"

# 2) しきい値を超えるファイルは rclone cat → split で分割しつつ、
#    分割ファイルを rclone rcat でそのまま S3 へ PUT(中間ファイルを作らない)
rclone lsf -R --files-only --min-size "$CHUNK_BYTES" "$SRC" \
  | tr '\n' '\0' \
  | xargs -0 -P "$JOBS" -I{} bash -euo pipefail -c '
      REL="$1"
      STEM="${REL##*/}"; STEM="${STEM%.*}"
      rclone cat "${SRC}${REL}" \
        | split -C "${CHUNK_BYTES}" - chunk- \
            --numeric-suffixes=1 --suffix-length=5 \
            --additional-suffix=.jsonl \
            --filter "rclone rcat \"${DST}${STEM}-\$(basename \$FILE)\""
      rclone deletefile "${SRC}${REL}"
    ' bash "{}"

split--filterオプションを使うことで分割ファイルをディスクに書き出さず、rclone rcatで直接S3へPUTできます。これによりPodの一時ストレージを使い切らずに済み、xargs -Pによって並列実行することで転送時間も抑えています。

ファイル分割により、1ファイルあたりの処理時間がLambdaのタイムアウト以内に収まり、ベクトル化Lambdaが安定して動作するようになりました。

出力形式と後処理

ベクトル化Lambdaは、JSONから対象テキストを取り出してベクトル化し、元のフィールドの代わりにベクトル用フィールドを追加した上で、JSON Lines形式でS3の別パスに出力します。OpenSearch投入用Lambda側のSQSがそのパスのS3作成イベントを受け取るようにし、後続の処理を行います。出力完了後は元ファイルを削除します。

OpenSearch投入Lambdaでの工夫

OpenSearch投入Lambdaは、ベクトル化済みデータが格納されたS3パスをSQS経由で受け取り、適切なバッチサイズにまとめてOpenSearchへ投入します。

external versionで古いデータで新しいデータを上書きすることを防止

差分更新の全体はDigdag workflowで管理していますが、WEAR全体のメンテナンスやインデクサーのエラーなどでジョブを再実行する可能性があります。その際、後の時間帯のデータを取得したジョブの後に、前の時間帯のデータを取得したジョブを実行する可能性があり、古いデータで新しいデータを上書きしてしまう懸念がありました。

これを防ぐため、OpenSearchのBulk APIversion / version_typeを渡し、external versionによって更新可否を判定できるようにしています。データ取得範囲の終了時刻をunixtimeに変換した値をversionとして持たせ、現在のversion以上の値の場合のみ更新が成立するようにしました。これにより、ジョブの実行順序が前後しても古いデータで上書きされることはなくなります。

unixtimeはOpenSearch投入Lambdaに渡されるS3キーのパスから算出しています。ベクトル化Lambdaが出力するS3キーはデータ取得範囲の終了時間を含んだ階層構造であり、それをパースしてversionとしています。

from opensearchpy import helpers

# OpenSearchへのbulk投入例(簡略化)
# 各アクションのメタデータに version / version_type を含めることで、
# external_versionより小さいversionの更新を拒否させる
# 更新処理にバグ等があった場合に再度同じ時間帯のデータで更新できるように、
# version_typeはexternal_gte(現在のversion以上のときのみ更新)を指定している
actions = [
    {
        "_op_type": "index",
        "_index": index_name,
        "_id": record["id"],
        "_source": record,
        "_version": external_version,
        "_version_type": "external_gte",
    }
    for record in records
]
helpers.bulk(client, actions)

なお、external versionはupsertに対応していないため5、差分更新ではdocument全体をreplaceする形で更新しています。

日次更新のOpenSearch Ingestionではexternal versionを利用できませんが、upsertすることでversionが+1される形で更新されます。

差分更新と日次更新でデータ投入のタイミングが前後する可能性はありますが、日次で更新する値は仮に古い値で更新されても致命的な問題にはならない内容のため許容しています。

処理完了後のファイル削除

OpenSearchへの投入が完了したファイルはS3から削除します。これは後述する非同期処理の完了待機の仕組みのためでもあります。

Lambdaエラー時のファイル退避

差分更新のLambdaでエラーが発生し、SQSの最大リトライ回数を超えた場合はerror/パスへファイルを移動させています。これにより後述する完了待機が止まらないようにしつつ、後でエラーになったファイルを追跡できるようにしています。

ただし、Lambdaがタイムアウトで終了した場合はerror/パスへの移動前に終了してしまいます。その結果、SQSのDLQにメッセージが残ったまま、元ファイルがS3に残ったままとなり、Digdag workflowの完了待機が永遠に終わらなくなります。

これを補完するため、定期的にSQSのDLQを監視し、error/パスへ移動できていないファイルを検知して移動する補助Lambdaを別途用意しています。

非同期処理の完了待機

インデクサーには非同期処理が含まれており、Digdag workflow側からは処理がいつ終わったかを直接知る術がありません。そこで、Digdag workflow側では処理対象のS3パスを監視し、ファイルが残っていない状態になったら処理完了とみなす方式を取りました。完了待機を入れる理由は次の通りです。

  • Bedrockのクォータで詰まっている状況で次のジョブが走ると、SQSにファイルがどんどん溜まってしまう
  • すべての投入が完了したタイミングでindex refreshを呼び、検索に反映させる必要がある
    • refresh頻度が高いと日次更新時のCPU使用率に影響するため、自動refreshは無効化している

aws s3 lsコマンドでS3の対象パスをリストし、ファイルが存在しなければ処理完了とみなすロジックをシェルスクリプトで実装しています。

既存データに対する初回ベクトル化

新しいインデクサーをリリースする前に、既存の大量のdocumentにベクトルデータを付与する必要がありました。差分更新と日次更新のジョブを稼働させ始めるだけでは、その時点で過去に投稿された大量のdocumentにはベクトルデータが付かないままです。

そこで、初回ベクトル化用にAWS Step Functionsを作成し、次の手順で全データのベクトル化を実施しました。

  1. Step Functionsで全データのバッチベクトル化を実行
  2. OpenSearch Ingestionで全データをOpenSearchへ投入
  3. 差分更新・日次更新のジョブを稼働開始
  4. 1〜3の処理中に取りこぼした時間帯のデータを、差分更新のジョブで埋める

external versionの仕組みがあるため、4の時点で過去の時間帯のデータを後から流しても、すでに最新のデータが入っているdocumentが古いデータで上書きされてしまうことはありません。差分更新の設計時点で順序を気にしなくて良いようにしたことが、初回ベクトル化のフローでも生きました。

結果

Embulkを用いた構成から、OpenSearch Ingestionと自作Lambdaを組み合わせた構成へとインデクサーを刷新したことで、以下のような効果が得られました。

  • 日次更新のジョブが4〜6時間から1時間以内に短縮された
  • 10万件規模の大量データを流すケースでも、想定時間内に推論からupsertまで完了できるようになった
  • Embulkがメンテナンスモードになるタイミングと重なり、結果的にリプレイスも同時に行えた

まとめ

本記事では、WEARのあいまい検索リリースに伴って検索インデクシングシステムを刷新した話を紹介しました。差分更新ではOpenSearch IngestionのLambdaプロセッサで要件を満たせなかったため、S3とSQSを挟んで自作Lambdaで非同期に処理を進める構成に切り替えました。日次更新ではOpenSearch IngestionのS3スキャンを採用し、毎回起動・終了させるという形で、ユースケースに応じて使い分けました。

ベクトル検索を支えるバッチ処理を設計する上では、以下のような工夫が有効でした。

  • ベクトル化用のBedrockをアプリケーションとは別リージョンに逃がし、クォータを分離する
  • ファイル単位の処理量をあらかじめ転送段階で制御し、Lambdaの処理時間を短縮させる
  • external versionでジョブ実行順序の前後に対する耐性を持たせる
  • ベクトル化と投入をLambdaとして分割し、流量制御や障害の影響範囲を限定する

OpenSearch Ingestionの採用やベクトル検索のためのインデクサーの設計を検討している方の参考になれば幸いです。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com


  1. 元々はElasticsearchを使用していましたが、OpenSearchへ移行しました。詳細はWEARの検索基盤をElasticsearch 7.10.2からOpenSearch 2.19.0へ無停止で移行する ── ダブルライトとカナリアリリースによる段階的アプローチをご参照ください。
  2. あいまい検索のリリースに関する詳細は別記事で紹介予定です。
  3. 実際はフォークしてカスタマイズしたプラグインを使用しています。
  4. クォータの値は本記事の執筆時点のものです。最新の値はAmazon Bedrock サービスクォータ一覧をご参照ください。
  5. Bulk - OpenSearch Documentationversion_type=external 系を指定した場合、documentの作成または完全置換のみが対象になります。
カテゴリー