背景・目的
2026年8月5日、Amazon DynamoDB がネイティブなリアルタイムベクトル検索を一般提供(GA)しました。これまで DynamoDB に運用データを持つアプリケーションがベクトル検索を追加するには、専用のベクトルDBへデータをコピーし、両者間の同期パイプラインを維持する必要がありました。この構成は運用負荷・データ移動コスト・ライセンスコスト・大規模時のレイテンシ維持という4つの負担を生んでいました。
今回の機能追加により、ベクトル埋め込みを運用データと同じテーブルに同居させ、別ストアへの複製や同期パイプラインなしに DynamoDB 内で直接類似検索ができるようになります。この記事では、手を動かさずに技術的な全体像・設計上の判断ポイント・制約を整理します。
まとめ
| 項目 | 内容 |
|---|---|
| これは何 | DynamoDB テーブル内にベクトルインデックスを作成し、運用データと同居したまま近似最近傍(ANN)検索を実行できるネイティブ機能 |
| 何ができる | 別ベクトルDB+同期パイプラインを廃止し、1桁ミリ秒レイテンシ・99%+再現率のセマンティック検索を DynamoDB 単体で実現できる |
| 設計の非可逆点 | 距離関数と射影の INCLUDE 属性は作成後に変更不可。代表データで検証してからインデックスを確定する |
| スケール設計 | パーティションキー(HASH)定義が水平スケールの鍵。未定義だと全体検索になりデータ増加に伴いレイテンシが悪化する |
| 主な制約 | On-demand 必須、インラインフィルタは等価のみ、Top K 最大100、DAX 非対応、Global tables はリージョン間で結果が厳密一致しない |
概要
用語の整理
| 用語 | 意味 |
|---|---|
| 埋め込み(embedding) | テキストや画像を固定長の数値ベクトルに変換したもの。意味が近いデータほど空間上で近くに位置する |
| ANN(Approximate Nearest Neighbor) | 近似最近傍探索。厳密な全件比較ではなく、高速に「ほぼ最も近い」結果を返すアルゴリズム |
| Vector index | DynamoDB に新設されたインデックス種別。GSI/LSI と同列の概念だが、完全一致・範囲ではなく類似検索(ANN)に使う |
| SearchVectors | Vector index に対して類似検索を実行する新しい API |
なお、ここでの「ベクトル」は ML モデルが生成する埋め込みベクトル(float の配列)を指します。DynamoDB 内部のストレージエンジンや Redshift 等で使われる「ベクトル化処理(vectorized execution = 列指向バッチ処理)」とは無関係です。
Vector index の位置づけ
Vector index は GSI/LSI と並ぶ新しいインデックス種別です。既存の CreateTable / UpdateTable API で管理します。
| 特性 | Vector index | GSI | LSI |
|---|---|---|---|
| クエリ種別 | 類似検索(ANN) | 完全一致・範囲 | 完全一致・範囲 |
| 読み取り API | SearchVectors | Query / Scan | Query / Scan |
| テーブルあたり最大 | 5 | 20 | 5 |
| キャパシティモード | On-demand のみ | On-demand / Provisioned | On-demand / Provisioned |
Vector indexes use an on-demand capacity mode that provisions and adjusts capacity based on demand.
(訳: Vector index はオンデマンドキャパシティモードで動作し、需要に応じて容量を自動的にスケールします。)
DynamoDB テーブルに Vector index を作成するには、テーブル自体が On-demand キャパシティモードである必要があります。
埋め込みの格納
埋め込みは float の List 型として通常の PutItem / UpdateItem で格納します。新しいデータ型もスキーマ変更も不要です。任意の埋め込みモデル(Amazon Bedrock Titan Text Embeddings、Cohere Embed、OpenAI text-embedding など)で生成したベクトルをそのまま書き込めます。次元数は最大 4,096 まで対応します。
距離関数(作成後は変更不可)
インデックス作成時に距離関数(DistanceFunction)を1つ選びます。作成後は変更できないため、代表データで再現率を検証してから確定することが重要です。
| 距離関数 | スコアの意味 | 主な用途 |
|---|---|---|
| COSINE | cosine distance(= 1 - cosine similarity)を返す。値域 0〜2 で、0 が完全一致方向。小さいほど類似 | テキスト埋め込みのセマンティック検索・RAG。方向のみ比較し magnitude を無視する |
| DOT_PRODUCT | 大きいほど類似(負値あり得る) | レコメンド等で、意図的にベクトル長に重みづけ情報を載せている場合 |
| EUCLIDEAN | 小さいほど類似 | 画像・音声。近似重複検出・クラスタリング・異常検知など絶対位置が意味を持つ場合 |
正規化済みベクトル(多くの埋め込みモデルのデフォルト出力)では COSINE と DOT_PRODUCT は数学的に同値になります。DOT_PRODUCT が差を生むのは、意図的に正規化を解除しベクトル長に意味を持たせた場合のみです。
原則として、埋め込みモデルが学習時に使った距離関数に合わせるとベストな精度が出ます。多くのテキスト埋め込みモデルは COSINE 前提で学習されているため、迷ったら COSINE が安全な既定です。
SearchSchema(パーティションキー / インラインフィルタ)
Vector index の検索範囲とフィルタ方法を制御する設計要素です。
HASH(Vector index パーティションキー):
- インデックスデータを分割し独立にスケールさせる
- 各 SearchVectors リクエストは単一パーティションキー値の範囲内で検索される
- Category や Country など低〜中カーディナリティ(数十〜数千値程度。1パーティションあたり数千〜数十万ベクトルに収まる粒度が目安)の属性を1つ指定
- 指定した場合は検索時に SearchConditionExpression で値の指定が必須
- 未定義だと毎回インデックス全体を検索する(シンプルだが水平スケールしない)
INLINE_FILTER:
- インデックスに射影され、ストレージ層で検索時にフィルタできる
- 等価(=)のみ対応。範囲・IN・BEGINS_WITH は未対応
- 検索時は任意(省略可)
大規模・高スループットを想定するなら HASH の定義を推奨します。マルチテナント構成やマーケットプレイス別など、検索範囲が自然に単一キー値に限定されるユースケースに向いています。
SearchVectors API
- 入力: クエリベクトル、返す件数(最大100)、任意のフィルタ条件
- 出力: 類似度スコアでランク付けされた結果。同一レスポンスで射影された運用属性(name、price 等)も返る
- 射影(Projection): KEYS_ONLY / INCLUDE / ALL。INCLUDE の属性集合は作成後に変更不可
他機能との併用
| 機能 | 対応状況 | 注意点 |
|---|---|---|
| DynamoDB Streams | 有効化可 | ストリームはベース表の変更を捕捉。インデックスとは独立に動作 |
| Global tables | Vector index 追加可 | 定義はレプリカへ自動複製。ただし ANN+非同期複製ゆえリージョン間で結果が厳密一致しない |
| PITR / バックアップ | 対応 | 復元時にインデックスを再構築(backfill)。IndexStatus=ACTIVE を待つ |
| TTL | 伝播する | 期限切れアイテムはインデックスからも削除される |
| Import/Export | 対応 | エクスポートにベクトル属性も含まれる。インポート時にインデックス定義を指定 |
| DAX | 非対応 | SearchVectors は DAX を経由できない。DynamoDB 本体に直接送る |
実践
この実践編の手順は 2026-08-05 GA 時点の公式ドキュメントに基づくコマンド例です。全手順を AWS CLI 2.36.13 / ap-northeast-1 で検証済みです。
1. テーブル作成と Vector index の定義(検証済み)
既存テーブルへの追加も可能ですが、ここでは新規作成の例を示します。
aws dynamodb create-table \
--table-name ProductCatalog \
--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=product-embeddings-index,VectorAttribute={AttributeName=Embedding},SearchSchema=[{AttributeName=Category,SearchSchemaElementType=HASH},{AttributeName=Brand,SearchSchemaElementType=INLINE_FILTER}],Projection={ProjectionType=ALL},Dimensions=1536,DistanceFunction=COSINE'
JSON 形式で渡したい場合は --cli-input-json を使います:
create-table.json:
{
"TableName": "ProductCatalog",
"AttributeDefinitions": [
{"AttributeName": "ProductId", "AttributeType": "S"},
{"AttributeName": "Category", "AttributeType": "S"},
{"AttributeName": "Brand", "AttributeType": "S"}
],
"KeySchema": [
{"AttributeName": "ProductId", "KeyType": "HASH"}
],
"BillingMode": "PAY_PER_REQUEST",
"VectorIndexes": [
{
"IndexName": "product-embeddings-index",
"VectorAttribute": {"AttributeName": "Embedding"},
"SearchSchema": [
{"AttributeName": "Category", "SearchSchemaElementType": "HASH"},
{"AttributeName": "Brand", "SearchSchemaElementType": "INLINE_FILTER"}
],
"Projection": {"ProjectionType": "ALL"},
"Dimensions": 1536,
"DistanceFunction": "COSINE"
}
]
}
aws dynamodb create-table --cli-input-json file://create-table.json
ポイント:
-
Dimensions: 使用する埋め込みモデルの次元数に合わせる(Titan Text Embeddings V2 はデフォルト 1024、text-embedding-3-small は 1536) -
DistanceFunction: 作成後に変更不可 -
SearchSchema:SearchSchemaElementTypeに HASH または INLINE_FILTER を指定 - SearchSchema で参照する属性(Category, Brand)は
AttributeDefinitionsにも宣言が必要
テーブル作成後、インデックスのステータスを確認します。ACTIVE になるまで SearchVectors は使えません。
aws dynamodb describe-table --table-name ProductCatalog \
--query "Table.{Status:TableStatus,VectorIndexes:VectorIndexes[0].IndexStatus}"
{
"Status": "ACTIVE",
"VectorIndexes": "ACTIVE"
}
レスポンスの VectorIndexes 配列に IndexStatus: "CREATING" → "ACTIVE" と遷移するのを確認しました。
2. 埋め込みの書き込み(検証済み)
通常の PutItem で float の List 型として格納します。ベクトルは要素数が多いため、公式ドキュメントの推奨に従い JSON ファイルに保存して渡します。
item.json(実際には 1536 要素。ここでは3要素に省略):
{
"ProductId": {"S": "prod-001"},
"Name": {"S": "ワイヤレスイヤホン"},
"Category": {"S": "Electronics"},
"Brand": {"S": "AudioTech"},
"Price": {"N": "12800"},
"Embedding": {
"L": [
{"N": "0.0123"},
{"N": "-0.0456"},
{"N": "0.0789"}
]
}
}
aws dynamodb put-item \
--table-name ProductCatalog \
--item file://item.json
実際には 1536 次元分の float を格納します。埋め込みの生成は Amazon Bedrock の InvokeModel API などで事前に行います。ベクトルの次元数がインデックスの Dimensions と一致しない場合、書き込みは拒否されます。
3. SearchVectors による類似検索(検証済み)
検索クエリベクトルは JSON ファイルに保存して渡します。ベクトルは DynamoDB の L 型ではなく、[{"N": "値"}, ...] のプレーンな JSON 配列で指定します。
query-vector.json(実際にはインデックスの Dimensions と同じ要素数。ここでは3要素に省略):
[
{"N": "0.0111"},
{"N": "-0.0222"},
{"N": "0.0333"}
]
aws dynamodb search-vectors \
--table-name ProductCatalog \
--index-name product-embeddings-index \
--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\": \"AudioTech\"}}"
実測レスポンス:
{
"SearchResults": [
{
"Item": {
"ProductId": {"S": "prod-001"},
"Price": {"N": "12800"},
"Brand": {"S": "AudioTech"},
"Category": {"S": "Electronics"},
"Name": {"S": "ワイヤレスイヤホン"}
},
"Score": 0.9797492623329163
}
]
}
-
--search-vector:file://でベクトルファイルを参照(インラインでの長大配列入力を回避) -
--top-k: 最大 100 - HASH 定義済みの場合、SearchConditionExpression でパーティションキー値の指定が必須
- Score は COSINE distance(0 が最も類似、2 が最も非類似)。今回はランダムベクトル同士のため 0.98 と高い値(≒ 類似度が低い)になっている
- Embedding 属性はデフォルトでレスポンスから除外される(Projection: ALL でも)。必要な場合は
ProjectionExpressionで明示的に指定する
レスポンスには各アイテムの類似度スコアと射影された属性が含まれます。
考察
- 最大の価値は「別ベクトルDB+同期パイプラインの廃止」。DynamoDB に運用データが既にある構成なら、専用ベクトルストアの導入・同期・ライセンス・二重課金をまとめて削減できる
- AI エージェントのメモリを DynamoDB に置く構成では、同じテーブル上でセマンティック検索(エージェント自身の記憶からの文脈検索)もできるため、相性が良い
- 設計の非可逆点(距離関数・射影の INCLUDE 属性)は最初に決め切る必要がある。代表データで再現率を検証し、埋め込みモデルの推奨距離関数に合わせてから確定する
- インラインフィルタが等価のみという制約は「価格帯で絞る」「日付範囲で絞る」といったユースケースで効いてくる。範囲フィルタが必要なら、アプリ側で後フィルタするか、Top K を多めに取って絞る設計が必要
- パーティションキー設計がスケール設計そのもの。マルチテナント・リージョン別など自然にスコープできるなら HASH を定義する。HASH の後付けはインデックスの削除+再作成(backfill 待ち)が必要で、本番データ量が大きい場合は数時間のダウンタイム相当になる。成長見込みがあるなら初期から HASH を定義しておく方が安全
- 同日(8/6付近)に Aurora Serverless の高速スケール、S3 Vectors のリージョン拡大も発表されており、「エージェント/AI 基盤としての AWS データサービス強化」という文脈で理解すると全体像が見える
参考