DynamoDB のベクトル検索
DynamoDB は 2026 年 8 月 5 日にネイティブのベクトル検索を獲得しました。埋め込みをアイテム上の Number 値の普通の List として保存し、ベクトルインデックスを追加すれば、新しい SearchVectors API で近似最近傍クエリを実行できます。
これまで、類似検索といえばテーブルを OpenSearch や別のベクトルデータベースへ複製し、両者を同期に保つことを意味しました。そのパイプラインは不要になりました。そして、それに代わる課金モデルは DynamoDB の他のどれとも似ていません。
DynamoDB はベクトル検索に対応していますか?
はい — 2026 年 8 月 5 日からネイティブに対応しています。埋め込みを Number 値の普通の
List として保存し、ベクトルインデックスを追加して、SearchVectors API
で近似最近傍クエリを実行します — OpenSearch
のレプリカも、別のベクトルデータベースも要りません。対応はオンデマンドテーブルのみ、最大
4,096 次元で、書き込み・検索・保存したバイト数に応じて課金されます。
- 第 3 のインデックスファミリー: ベクトルインデックスは と LSI の隣に並びます。新しい読み取り API は 1 つ(
SearchVectors)、ANN のみ、オンデマンドテーブルのみ、最大 4,096 次元です。 - 速い、しかも計測済み: us-east-1 の私たちのライブな 1024 次元インデックスに対して、
SearchVectorsは同じクライアントからのGetItemと同じ速さで応答し(p50 39 ms 対 44 ms)、書き込んだばかりのベクトルは約 136 ms で検索可能になりました。 - 計測はバイト単位: ベクトル書き込みは GB あたり $0.52、検索が調べるベクトルデータは GB あたり $0.002、ストレージは GB-月あたり $0.25(us-east-1)。埋め込みをインデックス化すると、そのベーステーブル側のコピーは次元あたりちょうど 4 バイトで課金されるようになります。同じリストは、インデックスなしでは約 1.9 倍で課金されます。
- バルクストアは依然として S3 Vectors: 保存はおよそ 8 分の 1 の安さで、バッチロードもはるかに安価です。DynamoDB が勝つのは、ミリ秒の読み取り、ストリーミング書き込み、そしてベクトルがその説明するアイテムのすぐ隣に住むことです。
ベクトルインデックスの仕組み
新しい属性型はありません。埋め込みはアイテム上の普通の数値のリストで、ワイヤ上では {"L": [{"N": "0.0132"}, {"N": "-0.0475"}, …]} となり、すでに使っている同じ PutItem と UpdateItem で書き込まれます。
インデックスは別個の構造です。DynamoDB はベクトルを 32 ビット float 精度で、射影またはフィルターに使う属性とともに、そこへ非同期にレプリケートします。検索結果は の読み取りと同じく結果整合性です。
この遅延は、実際には小さいものです。私たちのライブテストインデックスでは、書き込んだばかりのベクトルは PutItem が返ってから約 136 ms 後に検索結果に現れました。それでも、自分の書き込みをすぐ読み返すフローをこの上に構築するのは決してやめましょう。
既知のインデックスタイプの隣にどう位置づくか:
| ベクトルインデックス | GSI | LSI | |
|---|---|---|---|
| テーブルあたりの最大数 | 5 | 20 | 5 |
| 読み取り API | SearchVectors | Query、Scan | Query、Scan |
| PartiQL | いいえ | はい | はい |
| キャパシティモード | オンデマンドのみ | 両方 | 両方 |
| 整合性 | 結果整合性 | 結果整合性 | 強力な整合性が可能 |
| テーブル作成後の追加 | はい | はい | いいえ |
各インデックスは、作成時に次元数(最大 4,096)と 3 つの距離関数のうち 1 つを固定します。COSINE と EUCLIDEAN はスコアが低いほど類似、DOT_PRODUCT は高いほど類似で、負にもなりえます。どれも後から変更できません。
何かをベンチマークする前に、精度についての注意が 1 つあります。インデックスはベクトルを f32 で保持します。より高精度の値も受け入れられますが、取り込まれる過程で精度を失います。float64 の埋め込みで到着するなら、すべての距離は f32 のコピーに対して計算されるので、リコールは元の値に対してではなく f32 に対して測ってください。
作成して検索する
サポートチケットに対するセマンティック検索を運用していて、エージェントがキーワード一致なしで「以前これに遭遇した顧客」を見つけられるようにしたいとします。各チケットアイテムは件名と本文の埋め込みを持ち、それは好きなモデルで生成できます(Titan Text Embeddings V2 は Bedrock で入力 100 万トークンあたり $0.02)。
既存のテーブルにインデックスを追加します。HASH 要素はすべての検索を 1 つの product 値にスコープし、INLINE_FILTER 属性(最大 18 個)は検索時の等価フィルターを可能にします。
aws dynamodb update-table \
--table-name SupportTickets \
--attribute-definitions AttributeName=product,AttributeType=S \
AttributeName=severity,AttributeType=S \
--vector-index-updates '[{"Create": {
"IndexName": "TicketEmbeddings",
"VectorAttribute": {"AttributeName": "embedding"},
"SearchSchema": [
{"AttributeName": "product", "SearchSchemaElementType": "HASH"},
{"AttributeName": "severity", "SearchSchemaElementType": "INLINE_FILTER"}
],
"Projection": {"ProjectionType": "KEYS_ONLY"},
"Dimensions": 1024,
"DistanceFunction": "COSINE"
}}]'ビルドは、より鋭いエッジを持つ GSI バックフィルのように振る舞います。ビルドの間じゅう SearchVectors は ValidationException を返し、部分的な結果はありません。
AWS は、DescribeTable が ACTIVE と言った後もしばらく検索エンドポイントが拒否し続けうると警告しています。ウェイターはありません。リトライループの中で実際の検索を投げて探ってください。私たちが空のテーブルと同時にインデックスを作成したときは、26 秒で ACTIVE になり、その 0.6 秒後には検索を受け付けました。
検索は、クエリ埋め込みを {"N": …} 値の裸の JSON 配列として受け取ります。DynamoDB の L で包んではいけません。保存された属性はリスト型を使い、リクエストパラメータは使いません。この 2 つの取り違えは、ありがちな最初のミスです。
aws dynamodb search-vectors \
--table-name SupportTickets \
--index-name TicketEmbeddings \
--search-vector file://query-embedding.json \
--top-k 5 \
--search-condition-expression "product = :p AND severity = :sev" \
--expression-attribute-values '{":p": {"S": "checkout"}, ":sev": {"S": "high"}}'最も類似したものから順にソートされた最大 TopK 件のアイテムが、それぞれ Score 付きで返り、求めれば ConsumedCapacity も付いてきます。TopK の上限は 100 で、ページネーションはなく、レスポンスの上限は 16 MB です。
埋め込み自体は、射影したうえでリクエストしない限り結果から除外されます。このデフォルトは意図的なものです。ベクトルを返すことは、レスポンスと検索の請求の両方を膨らませます。
フィルター式は等価のみを受け付け、BETWEEN、IN、begins_with はありません。インデックスが HASH 属性を定義している場合、すべての検索はそれにちょうど 1 つの値を固定しなければなりません。範囲演算子についての AWS の言い回しは「not yet available」なので、これは緩和されるかもしれません。
最初のデプロイの前に知っておく価値のある運用上のサプライズが 2 つあります。SearchVectors には新しい dynamodb:SearchVectors IAM アクションが必要で、既存の読み取りポリシーのどれにも含まれていません。
さらに、別個のエンドポイント search-dynamodb.{region}.amazonaws.com と通信します。dynamodb.{region} だけをカバーするエグレス許可リストや VPC エンドポイント設定は、ベクトル検索だけを壊し、理由を決して語らない接続エラーを出します。
ベクトルインデックスの課金
新しいメーターは 3 つ、すべてバイト単位でリクエストあたり 1 KB の最低課金があり、通常のテーブル料金の上に載ります(us-east-1、AWS 料金 API より、2026-08-15):
| メーター | 標準 | Standard-IA |
|---|---|---|
| ベクトル書き込み | $0.52/GB | $0.65/GB |
| 検索ごとに調べられるベクトルデータ | $0.002/GB | $0.0025/GB |
| ストレージ(テーブルとインデックス) | $0.25/GB-月 | $0.10/GB-月 |
ドキュメントは、List の中の 10 進文字列として保存される埋め込みのベーステーブル側のコピーが、インデックス内の f32 コピーより「considerably larger」(かなり大きく)なりうると警告しています。私たちは us-east-1 のライブなテーブルに対して書き込みユニットの課金を計測しました。そして真実はもっと奇妙でした。
ベクトルインデックスのない属性上の埋め込みは、文書化された 10 進ルールどおり、およそ f32 サイズの 1.9 倍で課金されます。その同じ属性にベクトルインデックスを向けると、ベーステーブル側の課金は次元あたりちょうど 4 バイトまで下がります:
| 次元数 | インデックスなしの List 属性(課金) | 同じ属性、ベクトルインデックスあり(課金) |
|---|---|---|
| 256 | 1,914 B | 1,024 B |
| 768 | 5,760 B | 3,072 B |
| 1,024 | 7,653 B | 4,096 B |
| 1,536 | 11,501 B | 6,144 B |
| 3,072 | 22,957 B | 12,288 B |
パディング属性を使って書き込みユニットの境界を二分探索し、書き込みごとに新しいアイテムキーを使い、バイト単位まで較正して計測しました。私たちのフル 1024 次元のチケットアイテムは 5 書き込みユニットを課金しました。embedding にインデックスのない同一のアイテムは 8 を課金します。
同じ計測の中で、ベクトル書き込みのメーターは f32 サイズを忠実に追跡しました。VectorWriteRequestBytes は、裸のインデックスでは次元あたり 4 バイトにキーのオーバーヘッド 11 B を加えた値、私たちの 2 属性の検索スキーマ付きでは 65 B を加えた値で返ってきました。
検索課金は、事前に計算できないメーターです。VectorSearchRequestBytes は ANN トラバーサルが調べたベクトルデータの量を追跡し、AWS 自身のガイダンスは、次元数から見積もるのではなく ReturnConsumedCapacity で測ることです。
私たちのプローブが最初のデータポイントを与えてくれます。50 ベクトルのパーティションに対する TopK=10 は検索あたり 22.2〜22.4 KB を調べました。1 ベクトルのパーティションに対する同じ検索でも 21.4 KB を調べたので、小さなスケールではクエリあたりおよそ 21 KB(約 $0.00000004)の下限があります。AWS のチュートリアルは、自社の 50 ベクトルの例について 31,449 バイトを報告しています。
テーブル側のコストは料金計算ツールでモデル化してください。ベクトルのメーターは、そこですでに計算される書き込みユニットの上に積み重なります。
DynamoDB ベクトル検索 vs S3 Vectors
AWS は今や 2 つのサーバーレスなベクトルストアを売っており、両者は正反対のアクセスパターンのために作られています。S3 Vectors(2025 年 12 月 GA)はインデックスあたり最大 20 億ベクトルを $0.06/GB-月で保持し、100 ミリ秒から 1 秒の範囲で応答し、すべてのクエリをインデックス全体のサイズに対して課金します。
DynamoDB はミリ秒で応答し、インデックスが保持するものではなく、検索が調べたものに対して課金します。
| DynamoDB ベクトル検索 | S3 Vectors | |
|---|---|---|
| GA | 2026 年 8 月 | 2025 年 12 月 |
| レイテンシー階級 | 一桁ミリ秒(AWS の主張) | 頻繁アクセスで約 100 ms、低頻度で 1 秒未満(AWS の主張) |
| スケール上限 | ベクトル数の明示された上限なし。インデックス作成には 600 GB のテーブル上限(ソフト) | インデックスあたり 20 億ベクトル |
| 最大次元数 | 4,096 | 4,096 |
| 距離関数 | コサイン、ユークリッド、ドット積 | コサイン、ユークリッド |
| インデックス書き込み | テーブルから非同期(結果整合性) | 強力な整合性 |
| フィルタリング | 等価のみ、属性 18 個以下 + パーティションキー 1 個 | リッチなメタデータフィルター、ベクトルあたりフィルター可能 2 KB 上限 |
| TopK | 100、ページネーションなし | 10,000、ページネーションあり |
| ストレージ | $0.25/GB-月、2 回分(テーブル + インデックス) | $0.06/GB-月、1 回分 |
| 書き込み | $0.52/GB、リクエストあたり最低 1 KB | $0.20/GB、PUT あたり最低 128 KB |
| クエリ | 調べた分に対して $0.002/GB | リクエスト 100 万件あたり $2.50 + インデックス全体の処理バイト課金 |
ストリーミングのケースを決めるのは書き込みの最低課金で、それはストレージ料金とは逆の方向を指しています。1024 次元のベクトルを 1 件ずつ書き込む場合の、書き込み 100 万件あたりのコスト(検証済みの料金と、私たちが計測したアイテムあたり 5 書き込みユニット + 4,161 ベクトル書き込みバイトから算出):
| 書き込みパターン | DynamoDB | S3 Vectors |
|---|---|---|
| ベクトル 1 件ずつの書き込み | 約 $5.14/M | 約 $24.41/M |
バッチ(PutVectors あたり 500 件) | n/a(書き込みはアイテム単位) | 約 $0.78/M |
S3 の PUT あたり 128 KB の最低課金は、みんなが「安いはず」と思い込んでいるまさにそのワークロードにおいて、S3 を高価な選択肢にします。ベクトルを 1 件ずつ S3 Vectors にストリームすると DynamoDB の料率のほぼ 5 倍を支払い、バッチロードすればおよそ 7 分の 1 で済みます。
1024 次元のコーパスに月 100 万クエリをかけた場合の月間ストレージとクエリの合計を、検証済みの料金から算出しました(書き込みコストは上の 100 万件あたりの表です)。S3 Vectors のクエリ課金は公開された式、すなわちインデックス全体のサイズ × 段階制の料率に従います。
DynamoDB のクエリ課金は調べたバイト数に依存するので、あなたのトラバーサルを知っているふりをする代わりに、感度レンジを示します:
| コーパス | DynamoDB ストレージ | DynamoDB クエリ(調べたのが 4 / 40 / 400 MB の場合) | S3 Vectors ストレージ | S3 Vectors クエリ |
|---|---|---|---|---|
| 100 万ベクトル | 約 $1.95 | $8 / $80 / $800 | 約 $0.23 | 約 $11 |
| 1,000 万ベクトル | 約 $19.50 | $8 / $80 / $800 | 約 $2.35 | 約 $80 |
| 1 億ベクトル | 約 $195 | $8 / $80 / $800 | 約 $23.50 | 約 $217 |
この表から 2 つのことが読み取れます。DynamoDB のクエリあたりのコストはコーパスサイズとともには増えません — ANN 検索が調べるのは近傍であってインデックス全体ではなく、パーティションキーのスコープがそれをさらに縮めます。
S3 Vectors のストレージ優位(約 8 倍。DynamoDB は 4 倍の料率で 2 つの f32 コピーを保存するため)は、誰かがクエリするか否かにかかわらず、永遠に積み上がっていきます。
どちらを使うべきか
- ベクトルが、すでに DynamoDB に保持しているライブなアイテムを説明する(チケット、商品、ユーザーセッション、エージェントメモリ): ベクトルインデックスを使いましょう。書き込みパスは 1 つ、アイテムは 1 つ、ドリフトする同期パイプラインはありません。
- 数百万の埋め込みを、たまにクエリする(ドキュメントに対する RAG、アーカイブ、夜間ジョブ): S3 Vectors を使いましょう。安価にバッチロードし、保存には $0.06/GB を支払い、数百ミリ秒を許容します。
- ハイブリッドランキングを伴う高 QPS(テキスト関連度 + ベクトル、ファセット、集計): 答えは依然として OpenSearch です。従来型のサーバーレスコレクションで、およそ月 $350 のインフラ下限額がかかります。
- リレーショナルデータに結合されるベクトル: pgvector 付きの Aurora PostgreSQL です。ゼロまでスケールし、小さな RAG ワークロードなら月約 $50 未満に収まります。
DynamoDB ショップにとっての正直なデフォルトは両方です。ホットでフィルター可能なベクトルは、書き込みがアイテムとアトミックになるテーブル上に保ち、ロングテールは S3 Vectors へアーカイブしましょう。強力な整合性を持つバッチ書き込みが、S3 Vectors をきれいなシンクにしてくれます。
落とし穴
- 静かな脱インデックス: インデックスの
HASH属性を欠くアイテムは、テーブルへは問題なく書き込まれ、ベクトルインデックスには決して入りません。私たちはこれをライブで再現しました。PutItemは成功し、15 秒後もベクトルはどのパーティションにも存在しませんでした。エラーも、結果もなく、それを教えてくれるものはレスポンスに何もありません。 - 次元数の違う書き込みは拒否される: 移行せずに埋め込みモデルを切り替えると、すべての書き込みが、属性名と両方のサイズを名指しする
ValidationException(Invalid size for parameter、専用ページに逐語的に記録しています)で失敗します。インデックスは次元数を永久に固定するからです。 - 古くなった埋め込み: DynamoDB がベクトルを再計算することはありません。
embeddingを書き直さずにチケットのテキストを編集すると、検索は静かに古い内容に一致します。標準的な対処は、ストリームと再生成コンシューマーの組み合わせです。 TopKは常に K 件を返す: 良い一致が 3 件しかなくても、--top-k 10なら 10 件返ってきます。関連性は結果の件数ではなくScoreで判断し、スコアの向きが距離関数によって反転することを覚えておきましょう。- 1 KB の最低課金: 低次元のベクトルは、書き込みでも検索でも、比例して安くは計測されません。
- すべてがイミュータブル: 次元数、距離関数、そして
INCLUDE射影の属性セットは、どれも変更には削除と再作成が必要です。インデックスのストレージは、クエリされるか否かによらず、インデックスの生涯全体にわたって課金されます。
自分のテーブルで試す
ベクトル検索は、DynamoDB の他の部分があなたに教えたコスト規律を受け継ぎます。採用を決める前に埋め込みのサイズを測りましょう。アイテムサイズ制限は依然として適用され、3072 次元の埋め込みは、すべてのアイテム書き込みに対して、両方のメーターで 12 KB を上乗せするからです。
GSI が非同期にレプリケートされる仕組みと、LSI より GSI を選ぶべき場面を知っていれば、インデックスの挙動は馴染み深く感じられるでしょう。同じデータに対する字句検索については、DynamoDB には依然としてフルテキストエンジンがありません。ベクトル検索は綴りではなく意味に一致します。
埋め込みの実際のバイトコストをアイテムサイズ計算ツールで確かめ、それから DynoTable を試してベクトルインデックスの背後にあるアイテムをブラウズしてみましょう — 埋め込みは、フィルターに使うフィールドのすぐ隣に、普通のリスト属性として表示されます。