ベクトルインデックスの作成と検索
このセクションでは、SearchVectors API を使用してベクトルインデックスを作成および管理し、ベクトルデータを含む項目の書き込み、類似度検索を実行する方法について説明します。
トピック
開始する前に
ベクトルインデックスを使用する前に、以下を確認してください。
-
テーブルはオンデマンドキャパシティモード (
PAY_PER_REQUEST) を使用しています。ベクトルインデックスは、プロビジョニングされたキャパシティテーブルではサポートされていません。 -
AWS Identity and Access Management (IAM) ID には、ベクトルインデックスを作成するための
dynamodb:CreateTableまたはdynamodb:UpdateTableアクセス許可があります。 -
IAM ID には、検索を実行するためのベクトルインデックスリソースに対する
dynamodb:SearchVectorsアクセス許可があります。リソース ARN 形式はarn:aws:dynamodb:です。region:account-id:table/table-name/index/index-name
SearchVectors エンドポイント
SearchVectors リクエストは専用ベクトル検索エンドポイントを使用します。これは、ベクトルインデックスの作成と管理 (CreateTable、UpdateTable、DescribeTable など) に使用する標準の DynamoDB エンドポイントとは異なります。AWS SDK と AWS CLI は、SearchVectors リクエストを正しいエンドポイントに自動的にルーティングします。アプリケーションコードでエンドポイントを設定または上書きする必要はありません。
AWS SDK を使用せずに DynamoDB API を直接呼び出すカスタム HTTP クライアントを構築する場合は、account-id と region を適切に置き換えて、次のいずれかのベクトル検索エンドポイントを使用します。
-
– アカウントベースのエンドポイント。account-id.search-ddb.region.amazonaws.com -
search-dynamodb.– IPv4 と IPv6 の両方と互換性のあるデュアルスタックエンドポイント。region.api.aws
ベクトル埋め込みの生成
DynamoDB はベクトル埋め込みを保存して検索しますが、生成は行いません。Amazon Bedrock Titan Text Embeddings や Cohere Embed モデルなどの埋め込みモデル、またはお客様が運用する埋め込みモデルを使用して埋め込みを生成します。次に、生成されたベクトルを DynamoDB 項目に保存し、クエリベクトルを SearchVectors に渡します。
クエリベクトルと保存済みベクトルは、同じモデルを使用する必要があります
SearchVectors に渡すクエリベクトルと項目に保存されるベクトルは、同じ埋め込みモデルによって生成され、ベクトルインデックスと同じ数のディメンションを持つ必要があります。モデルを混在させたり、インデックス作成時とは異なるディメンション数でクエリを実行すると、意味のない結果が生じるか、検証エラーが発生します。
一般的なフローは次のとおりです。
-
ソースコンテンツ (製品説明など) を埋め込みモデルに送信し、ベクトルを受け取ります。
-
そのベクトルを、ベクトルインデックス (
VectorAttribute) で命名された属性に、数値 (N) のリスト (L) として DynamoDB 項目に保存します。 -
クエリ時に、同じモデルを使用して検索テキストからベクトルを生成し、
SearchVectorとして渡します。
インデックスを作成する前に埋め込みモデルを選択する
ベクトルインデックスを作成する前に埋め込みモデルを選択してください。モデルによってディメンション数が決まります。一般的な埋め込みモデルでは、384、768、1024、1536、または 3072 ディメンションが生成されます。DynamoDB は最大 4,096 ディメンションをサポートします。「要件と制限」を参照してください。
選択する距離関数は、モデルが埋め込みを生成する方法と相互作用します。COSINE は方向を比較し、大きさを無視するため、正規化されているかどうかにかかわらず埋め込みで機能します。DOT_PRODUCT は大きさの影響を受けます。埋め込みが単位長に正規化されていない場合、より大きなベクトルは方向に関係なくより高いスコアを得ることになります。DOT_PRODUCT を使用し、かつ方向ベースの類似性が必要な場合は、埋め込みを保存する前に単位長に正規化します。「距離関数による結果のランク付け」を参照してください。
ベクトルインデックスの作成
ベクトルインデックスは、新しいテーブルを作成するときに作成することも、既存のテーブルに追加することもできます。
ベクトルインデックスを持つテーブルの作成
VectorIndexes パラメータを指定して CreateTable API を使用し、ベクトルインデックスを持つテーブルを作成します。次の AWS CLI 例では、ProductEmbeddingIndex という名前のベクトルインデックスを持つ Products テーブルを作成します。
aws dynamodb create-table \ --table-name Products \ --attribute-definitions AttributeName=ProductId,AttributeType=S \ AttributeName=Category,AttributeType=S \ AttributeName=Brand,AttributeType=S \ --key-schema AttributeName=ProductId,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --vector-indexes \ "[ { \"IndexName\": \"ProductEmbeddingIndex\", \"VectorAttribute\": {\"AttributeName\": \"Embedding\"}, \"SearchSchema\": [{\"AttributeName\":\"Category\",\"SearchSchemaElementType\":\"HASH\"}, {\"AttributeName\":\"Brand\",\"SearchSchemaElementType\":\"INLINE_FILTER\"}], \"Projection\": {\"ProjectionType\": \"ALL\"}, \"Dimensions\": 1536, \"DistanceFunction\": \"COSINE\" } ]"
この例では、以下のようになっています:
-
VectorAttributeは、ベクトルデータを含む属性としてEmbeddingを指定します。 -
SearchSchemaは、ベクトルインデックスのパーティションキー (HASH) としてCategoryを定義します。これにより、スケーリングのためにカテゴリ別にインデックスがパーティション化されます。また、BrandをINLINE_FILTERとして定義します。これにより、ストレージレイヤーでブランド別に検索結果をフィルタリングできます。CategoryとBrandの両方が SearchSchema で参照されるため、グローバルセカンダリインデックスに対してキー属性を宣言するのと同じ方法で、AttributeDefinitionsでも宣言する必要があります。 -
Dimensionsは 1536 に設定され、一般的な埋め込みモデルの出力と一致します。 -
DistanceFunctionはCOSINEに設定され、スコアが低いほど類似度が高いことを示します。
ベクトルインデックスの既存テーブルへの追加
VectorIndexUpdates パラメータを指定して UpdateTable API を使用して、既存のテーブルにベクトルインデックスを追加します。この例では、同じ Products テーブルに ProductEmbeddingIndexV2 という名前の 2 つ目の独立したインデックスを追加します。
aws dynamodb update-table \ --table-name Products \ --vector-index-updates \ "[ { \"Create\": { \"IndexName\": \"ProductEmbeddingIndexV2\", \"VectorAttribute\": {\"AttributeName\": \"Embedding\"}, \"Projection\": {\"ProjectionType\": \"ALL\"}, \"Dimensions\": 1536, \"DistanceFunction\": \"EUCLIDEAN\" } } ]"
既存のテーブルにベクトルインデックスを追加すると、DynamoDB は DescribeTable レスポンスの 2 つのフィールド (IndexStatus 値と個別の Backfilling ブール値) を通じてインデックスの進行状況をレポートします。
-
IndexStatusはCREATINGです – DynamoDB はインデックスインフラストラクチャをセットアップしています。 -
IndexStatusはACTIVEで、Backfillingがtrueに設定されています – DynamoDB はベーステーブルの既存のデータを使用してインデックスに入力しています。ベーステーブルへの新しい書き込みも、このフェーズ中にインデックスにレプリケートされます。ベクトルインデックスがバックフィルされている間、SearchVectorsはエラーを返します。Backfillingがfalseになるまで待ってから検索します。 -
IndexStatusがACTIVEで、Backfillingがfalseに設定されている (または存在しない) – インデックスは完全に入力され、検索オペレーションが可能な状態です。
インデックスのバックフィル中は検索できません
SearchVectors は、ベクトルインデックスのバックフィル中にエラーを返します。DescribeTable を使用して IndexStatus フラグと Backfilling フラグの両方を確認し、IndexStatus が ACTIVE になり、Backfilling が false になるまで待ってから検索します。BACKFILLING というインデックスのステータス値はありません。
ベクトルデータを含む項目の書き込み
標準の DynamoDB 書き込み API (PutItem、UpdateItem、BatchWriteItem、TransactWriteItems) を使用して、ベクトルデータを含む項目を書き込みます。ベクトル埋め込みを数値のリスト (N 要素を含む L 型) として保存します。
ベクトルには多くの値が含まれているため、項目を item.json などのファイルに保存し、そのファイルを AWS CLI に渡します。
{ "ProductId": { "S": "prod-123" }, "Category": { "S": "Electronics" }, "Title": { "S": "Wireless Headphones" }, "Embedding": { "L": [ { "N": "0.1234" }, { "N": "-0.5678" }, { "N": "0.9012" }, ... ] } }
aws dynamodb put-item \ --table-name Products \ --item file://item.json
ベクトルの長さはインデックスのディメンションと一致する必要があります
ここに示す Embedding ベクトルは省略されています。item.json では、ProductEmbeddingIndex で設定した Dimensions と一致させるには、1,536 個の値が含まれている必要があります。ディメンション数が正しくないベクトルの書き込みは拒否されます。
DynamoDB は、ベクトルインデックスを持つテーブルに項目を書き込むときにベクトルデータを検証します。次の表は、検証動作の説明です。
| 条件 | 動作 |
|---|---|
| ベクトル属性のディメンション数が正しくありません | 書き込みは拒否されます。 |
| ベクトルインデックスのパーティションキー属性がありません | ベーステーブルへの書き込みは成功しますが、その項目はベクトルインデックスにレプリケートされません。 |
| ベクトルインデックスのパーティションキー属性の型がインデックススキーマと一致しません | 書き込みは拒否されます。 |
| インラインフィルター属性がありません | 書き込みは成功し、項目はベクトルインデックスにレプリケートされます。 |
| ベクトル値は 32 ビット浮動小数点 (f32) よりも高い精度を持ちます | 書き込みが成功します。値はベーステーブルにそのまま保存されますが、ベクトルインデックスにレプリケートする際には精度が低下します。 |
| ベクトル属性が項目から削除される | ベクトルインデックスの対応するエントリが削除されます。 |
パーティションキーがないと、サイレントなインデックス解除が発生します。
ベクトルインデックスが SearchSchema でパーティションキーを定義し、その属性なしで項目を書き込む (または UpdateItem で削除する) 場合、書き込みはベーステーブルで成功しますが、項目はベクトルインデックスからサイレントに除外されます。ベーステーブルの項目とそのベクトル埋め込みがまだ存在する場合でも、SearchVectors の結果には表示されません。検索対象とするすべての項目に、ベクトルインデックスのパーティションキー属性が含まれていることを確認します。
古い埋め込みでは誤った結果が生成されます
DynamoDB は、埋め込みを自動的に再計算することはありません。埋め込みを生成したソースコンテンツを変更した場合 (製品の説明を編集した場合など)、保存されたベクトルは自動的には更新されません。埋め込みモデルを使用して埋め込みを再生成し、新しいベクトルを項目に書き戻す必要があります。そうしないと、ベクトルインデックスは古いベクトルに基づいて結果を返し続けるため、誤った一致がサイレントに発生する可能性があります。
SearchVectors を使用した検索
SearchVectors API を使用して、クエリベクトルに最も近い項目をベクトルインデックス内で検索します。結果は関連性に基づいてソートされ、最も類似した項目が最初に表示されます。検索結果は結果整合性に基づいています。ベクトルの書き込みまたは更新から検索結果に表示されるまでに、わずかな遅延が発生する場合があります。詳細については、「継続的な書き込み同期」を参照してください。
基本的な検索
次の例では、ProductEmbeddingIndex インデックス内で最も類似している 10 個の項目を検索します。このインデックスには、SearchSchema でベクトルインデックスのパーティションキー (Category) が定義されているため、SearchConditionExpression にはベクトルインデックスのパーティションキー値を含める必要があります。
クエリベクトルを query-vector.json などのファイルに、数値のプレーン JSON 配列として保存します。
[ { "N": "0.1234" }, { "N": "-0.5678" }, { "N": "0.9012" }, ... ]
aws dynamodb search-vectors \ --table-name Products \ --index-name ProductEmbeddingIndex \ --search-vector file://query-vector.json \ --top-k 10 \ --search-condition-expression "Category = :cat" \ --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}}"
レスポンスには SearchResults 配列が含まれます。各要素には、一致する Item と、項目がクエリベクトルとどの程度類似しているかを示す Score が含まれます。
{ "SearchResults": [ { "Item": { "ProductId": { "S": "prod-456" }, "Category": { "S": "Electronics" }, "Title": { "S": "Bluetooth Speaker" } }, "Score": 0.0023 }, { "Item": { "ProductId": { "S": "prod-789" }, "Category": { "S": "Electronics" }, "Title": { "S": "Noise Cancelling Earbuds" } }, "Score": 0.0145 } ] }
ベクトル属性はデフォルトで結果から除外されます
デフォルトでは、SearchVectors からの結果にはベクトル属性 (埋め込み) は含まれません。ベクトルデータは大きく、通常はレスポンスでは必要ありません。結果には、他の射影された属性と Score 値が含まれます。ベクトル属性を含めるには、ProjectionExpression でリクエストします。詳細については、「ProjectionExpression の使用」を参照してください。
SearchVector はプレーンリストであり、DynamoDB L 型ではありません
SearchVector リクエストパラメータは、数値オブジェクトのプレーン JSON 配列 ([{"N": "0.1234"}, ...]) です。項目属性にベクトルを保存する場合のように、DynamoDB L 型でラップしないでください。L ラッパーは、項目属性でベクトルデータを書き込みまたは読み取る場合にのみ使用されます。
Score の意味は、インデックスの作成時に選択した距離関数によって異なります。COSINE と EUCLIDEAN の場合、スコアが低いほど類似度が高いことを示します。DOT_PRODUCT の場合、スコアが高いほど類似度が高いことを示します。
SearchConditionExpression を使用したフィルタリング
SearchConditionExpression を使用して、SearchSchema で定義されたベクトルインデックスのパーティションキーとインラインフィルター属性に基づいて検索結果をフィルタリングします。この式は、他の DynamoDB 式パラメータと同じ構文を使用します。
次の例では、Brand インラインフィルターを使用して Electronics カテゴリ (ベクトルインデックスのパーティションキー) 内の項目を検索します。
aws dynamodb search-vectors \ --table-name Products \ --index-name ProductEmbeddingIndex \ --search-vector file://query-vector.json \ --top-k 10 \ --search-condition-expression "Category = :cat AND Brand = :brand" \ --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}, \":brand\": {\"S\": \"Acme\"}}"
ベクトルインデックスに SearchSchema でパーティションキーが定義されている場合は、SearchConditionExpression に含める必要があります。インラインフィルター属性はオプションです。
SearchConditionExpression において、等価演算子 (=) は、ベクトルインデックスのパーティションキーとインラインフィルター属性の両方でサポートされています。比較、範囲、および集合メンバー演算子 (<>、<、<=、>、>=、IN) はまだ利用できません。
このフィルタリングは、類似度検索の範囲をデータのサブセットに絞り込むための手法であり、マルチテナントおよび検索拡張生成 (RAG) アプリケーションの一般的な要件です。例えば、クエリに似ているドキュメントを特定のテナント内でのみ検索するには、テナント属性を SearchSchema のベクトルインデックスのパーティションキー (HASH) として定義し、検索のたびにその値を渡します。これにより、結果をそのテナントのみに限定できます。また、関連するデータのみが検索されるため、パフォーマンスも向上します。ルーティングされたパーティション内に適用するドキュメントタイプやステータスなど、追加の等価制約にはインラインフィルター属性を使用します。
パーティションキーの範囲設定はセキュリティ境界ではない
パーティションキーを使用して検索の範囲を単一のテナントに絞り込むのは、アクセスコントロールメカニズムではなく、データの局所性やパフォーマンス最適化のための手法です。インデックスに対する dynamodb:SearchVectors アクセス許可を持つプリンシパルは、任意のパーティションキー値を検索できます。dynamodb:LeadingKeys などのきめ細かなアクセスコントロール (FGAC) 条件キーは SearchVectors には適用されないため、IAM ポリシーレベルで個々のパーティションキー値へのアクセスを制限することはできません。ワークロードがデータレイヤーで厳密なテナント分離を必要とする場合は、テナントごとに個別の IAM 許可を持つ個別のテーブルまたはインデックスを使用します。
ProjectionExpression の使用
ProjectionExpression を使用して、検索結果内の特定の属性のみを返します。これにより、すべての射影された属性を必要としない場合にレスポンスサイズを削減できます。ProductEmbeddingIndex は SearchSchema でベクトルインデックスのパーティションキー (Category) を定義するため、この例でも SearchConditionExpression にベクトルインデックスのパーティションキー値が含まれています。
aws dynamodb search-vectors \ --table-name Products \ --index-name ProductEmbeddingIndex \ --search-vector file://query-vector.json \ --top-k 5 \ --search-condition-expression "Category = :cat" \ --expression-attribute-values "{\":cat\": {\"S\": \"Electronics\"}}" \ --projection-expression "ProductId, Title"
射影された属性のみ返すことができます
ベクトルインデックスに射影された属性のみを返すことができます。インデックス射影にない属性は、SearchVectors によって返されません。
ベクトルインデックスの削除
VectorIndexUpdates パラメータを指定して UpdateTable API を使用し、ベクトルインデックスを削除します。
aws dynamodb update-table \ --table-name Products \ --vector-index-updates \ "[ {\"Delete\": {\"IndexName\": \"ProductEmbeddingIndex\"}} ]"
ベクトルインデックスを削除すると、DynamoDB はインデックスとそのすべてのデータを削除します。このオペレーションは、ベーステーブルまたはその項目には影響しません。