Pesquisa vetorial no DynamoDB
O DynamoDB ganhou pesquisa vetorial nativa em 5 de agosto de 2026. Você armazena embeddings como uma List simples de valores Number nos seus itens, adiciona um índice vetorial e executa consultas de vizinho mais próximo aproximado com a nova API SearchVectors.
Até agora, busca por similaridade significava replicar sua tabela no OpenSearch ou em um banco de dados vetorial separado e manter os dois em sincronia. Esse pipeline acabou. O modelo de faturamento que o substitui não se parece com nada no DynamoDB.
O DynamoDB suporta pesquisa vetorial?
Sim — nativamente, desde 5 de agosto de 2026. Você armazena embeddings como uma
List simples de valores Number, adiciona um índice vetorial e executa
consultas de vizinho mais próximo aproximado com a API SearchVectors — sem
réplica no OpenSearch, sem banco de dados vetorial separado. Funciona apenas em
tabelas sob demanda, até 4,096 dimensões, e é faturado por byte gravado,
pesquisado e armazenado.
- Uma terceira família de índices: índices vetoriais ficam ao lado dos e LSIs. Uma nova API de leitura (
SearchVectors), apenas ANN, apenas tabelas sob demanda, até 4,096 dimensões. - É rápido, medido: contra o nosso índice de 1024 dimensões ao vivo em us-east-1, o
SearchVectorsrespondeu tão rápido quanto oGetItema partir do mesmo cliente (p50 de 39 ms vs 44 ms), e uma gravação recém-feita ficou pesquisável em ~136 ms. - A medição é por byte: $0.52 por GB de gravações vetoriais, $0.002 por GB de dados vetoriais examinados por uma pesquisa, $0.25 por GB-mês de armazenamento (us-east-1). Indexar um embedding faz a cópia dele na tabela base faturar exatamente 4 bytes por dimensão; a mesma lista sem índice fatura ~1.9×.
- O S3 Vectors continua sendo o repositório em massa: cerca de 8× mais barato em repouso e muito mais barato para carregar em lote. O DynamoDB vence em leituras de milissegundos, gravações em streaming e vetores vivendo ao lado do item que descrevem.
Como funciona um índice vetorial
Não existe um novo tipo de atributo. Um embedding é uma lista comum de números no item, {"L": [{"N": "0.0132"}, {"N": "-0.0475"}, …]} na transmissão, gravada com os mesmos PutItem e UpdateItem que você já usa.
O índice é uma estrutura separada. O DynamoDB replica o vetor para ele de forma assíncrona com precisão de float de 32 bits, junto com quaisquer atributos que você projete ou use em filtros. Os resultados da pesquisa são eventualmente consistentes, como uma leitura de .
O atraso é pequeno na prática. Contra o nosso índice de teste ao vivo, um vetor recém-gravado apareceu nos resultados de pesquisa cerca de 136 ms depois que o PutItem retornou. Ainda assim, nunca construa um fluxo de ler-a-própria-gravação sobre isso.
Onde ele se posiciona ao lado dos tipos de índice que você conhece:
| Índice vetorial | GSI | LSI | |
|---|---|---|---|
| Máximo por tabela | 5 | 20 | 5 |
| API de leitura | SearchVectors | Query, Scan | Query, Scan |
| PartiQL | Não | Sim | Sim |
| Modo de capacidade | Apenas sob demanda | Ambos | Ambos |
| Consistência | Eventual | Eventual | Forte disponível |
| Adicionar após a criação da tabela | Sim | Sim | Não |
Cada índice fixa sua contagem de dimensões (até 4,096) e uma de três funções de distância na criação. COSINE e EUCLIDEAN pontuam menor-é-mais-similar; DOT_PRODUCT pontua maior-é-mais-similar e pode ficar negativa. Nada disso pode ser alterado depois.
Uma nota de precisão antes de você fazer qualquer benchmark. O índice guarda os vetores em f32; valores de precisão mais alta são aceitos mas perdem precisão na entrada. Se você chega com embeddings float64, toda distância é calculada contra a cópia f32, então meça o recall contra f32, não contra seus originais.
Crie um e pesquise nele
Digamos que você rode busca semântica sobre tickets de suporte, para que um agente encontre "clientes que já passaram por isso" sem casar palavras-chave. Cada item de ticket carrega um embedding do seu assunto e corpo, gerado por qualquer modelo que você quiser (o Titan Text Embeddings V2 custa $0.02 por milhão de tokens de entrada no Bedrock).
Adicione o índice à tabela existente. O elemento HASH limita cada pesquisa a um único valor de product; atributos INLINE_FILTER (até 18) permitem filtros de igualdade no momento da pesquisa:
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"
}}]'O build se comporta como um backfill de GSI com arestas mais afiadas. SearchVectors retorna ValidationException durante todo o build, sem resultados parciais.
A AWS avisa que o endpoint de pesquisa pode continuar rejeitando por um tempo mesmo depois que o DescribeTable diz ACTIVE. Não há waiter; sonde com uma pesquisa real em um loop de retry. Quando criamos o índice junto com uma tabela vazia, ele ficou ACTIVE em 26 segundos e aceitou pesquisas 0.6 s depois.
A pesquisa recebe o embedding de consulta como um array JSON puro de valores {"N": …}. Não o envolva em um L do DynamoDB. O atributo armazenado usa o tipo lista, o parâmetro da requisição não, e confundir os dois é um primeiro erro fácil:
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"}}'Você recebe de volta até TopK itens ordenados do mais similar para o menos, cada um com um Score, além de ConsumedCapacity quando você o solicita. TopK tem teto de 100, não há paginação e a resposta tem teto de 16 MB.
O próprio embedding é excluído dos resultados a menos que você o projete e o solicite. Esse padrão é deliberado; retornar vetores infla tanto a resposta quanto a conta da pesquisa.
Expressões de filtro aceitam apenas igualdade, sem BETWEEN, IN ou begins_with. Quando o índice define um atributo HASH, toda pesquisa deve fixar exatamente um valor para ele. A formulação da AWS sobre operadores de intervalo é "not yet available", então isso pode afrouxar.
Duas surpresas operacionais valem a pena conhecer antes do primeiro deploy. SearchVectors precisa da nova ação IAM dynamodb:SearchVectors, que nenhuma das suas políticas de leitura existentes inclui.
Ele também fala com um endpoint separado, search-dynamodb.{region}.amazonaws.com. Allowlists de egresso e configurações de VPC endpoint que cobrem apenas dynamodb.{region} quebram somente a pesquisa vetorial, com um erro de conexão que nunca diz o porquê.
O que um índice vetorial fatura
Três novos medidores, todos por byte, com um mínimo de 1 KB por gravação e por requisição de pesquisa, em cima das cobranças normais da tabela (us-east-1, da API de preços da AWS, 2026-08-15):
| Medidor | Standard | Standard-IA |
|---|---|---|
| Gravações vetoriais | $0.52/GB | $0.65/GB |
| Dados vetoriais examinados por pesquisa | $0.002/GB | $0.0025/GB |
| Armazenamento (tabela e índice) | $0.25/GB-mês | $0.10/GB-mês |
A documentação avisa que a cópia de um embedding na tabela base, armazenada como strings decimais dentro de uma List, pode ser "considerably larger" do que a cópia f32 no índice. Medimos o faturamento em unidades de gravação contra tabelas ao vivo em us-east-1, e a verdade é mais estranha.
Um embedding em um atributo sem índice vetorial fatura pela regra decimal documentada, cerca de 1.9× o tamanho f32. Aponte um índice vetorial para esse mesmo atributo e o faturamento dele na tabela base cai para exatamente 4 bytes por dimensão:
| Dimensões | Atributo List sem índice (faturado) | Mesmo atributo, indexado como vetor (faturado) |
|---|---|---|
| 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 |
Medido fazendo busca binária na fronteira de unidades de gravação com um atributo de preenchimento, chave de item nova a cada gravação, calibrado ao byte. Nosso item de ticket completo de 1024 dimensões faturou 5 unidades de gravação; o item idêntico sem um índice em embedding fatura 8.
O medidor de gravações vetoriais acompanhou de perto o tamanho f32 nas mesmas execuções. VectorWriteRequestBytes voltou como 4 bytes por dimensão mais 11 B de overhead de chave em um índice puro, e mais 65 B com o nosso search schema de dois atributos.
O faturamento da pesquisa é o medidor que você não consegue calcular de antemão. VectorSearchRequestBytes rastreia quantos dados vetoriais a travessia ANN examinou, e a orientação da própria AWS é medi-lo via ReturnConsumedCapacity em vez de estimar a partir da contagem de dimensões.
Nossa sondagem fornece os primeiros pontos de dados. TopK=10 sobre uma partição de 50 vetores examinou 22.2-22.4 KB por pesquisa; a mesma pesquisa sobre uma partição de 1 vetor ainda examinou 21.4 KB, então em pequena escala há um piso de cerca de 21 KB (aproximadamente $0.00000004) por consulta. O tutorial da AWS reporta 31,449 bytes para o seu próprio exemplo de 50 vetores.
Modele os custos do lado da tabela na calculadora de preços; os medidores vetoriais se empilham sobre as unidades de gravação que ela já calcula.
Pesquisa vetorial do DynamoDB vs S3 Vectors
A AWS agora vende dois repositórios vetoriais serverless, e eles foram construídos para padrões de acesso opostos. O S3 Vectors (GA em dezembro de 2025) comporta até 2 bilhões de vetores por índice a $0.06/GB-mês, responde na faixa de 100 ms a 1 s e fatura cada consulta contra o tamanho do índice inteiro.
O DynamoDB responde em milissegundos e fatura contra o que a pesquisa examina, não contra o que o índice contém.
| Pesquisa vetorial do DynamoDB | S3 Vectors | |
|---|---|---|
| GA | Ago 2026 | Dez 2025 |
| Classe de latência | Milissegundos de um dígito (alegação da AWS) | ~100 ms frequente, sub-1 s infrequente (alegação da AWS) |
| Teto de escala | Sem limite declarado de vetores; teto de 600 GB de tabela para criar o índice (soft) | 2B vetores por índice |
| Dimensões máximas | 4,096 | 4,096 |
| Funções de distância | Cosseno, euclidiana, produto escalar | Cosseno, euclidiana |
| Gravações no índice | Assíncronas a partir da tabela (eventualmente consistentes) | Fortemente consistentes |
| Filtragem | Apenas igualdade, ≤18 atributos + 1 chave de partição | Filtros de metadados ricos, teto de 2 KB filtráveis por vetor |
| TopK | 100, sem paginação | 10,000, com paginação |
| Armazenamento | $0.25/GB-mês, duas vezes (tabela + índice) | $0.06/GB-mês, uma vez |
| Gravações | $0.52/GB, mín. de 1 KB/requisição | $0.20/GB, mín. de 128 KB/PUT |
| Consultas | $0.002/GB examinado | $2.50/M requisições + cobrança de bytes processados do índice inteiro |
Os mínimos de gravação decidem o caso de streaming, e eles apontam na direção oposta às taxas de armazenamento. Gravando um vetor de 1024 dimensões por vez, por milhão de gravações (a partir das taxas verificadas e das nossas 5 unidades de gravação + 4,161 bytes de gravação vetorial medidos por item):
| Padrão de gravação | DynamoDB | S3 Vectors |
|---|---|---|
| Gravações de vetor único | ~$5.14/M | ~$24.41/M |
Em lote (500 por PutVectors) | n/a (gravações são por item) | ~$0.78/M |
O mínimo de 128 KB por PUT do S3 o torna a opção cara exatamente para a carga de trabalho que as pessoas presumem que ele é barato. Envie vetores um por vez em streaming para o S3 Vectors e você paga quase 5× a taxa do DynamoDB; carregue-os em lote e você paga cerca de 7× menos.
Totais mensais de armazenamento e consulta para um corpus de 1024 dimensões a 1M de consultas por mês, calculados a partir das taxas verificadas (os custos de gravação estão na tabela por milhão acima). A cobrança de consulta do S3 Vectors segue sua fórmula publicada, o tamanho do índice inteiro vezes uma taxa em camadas.
A cobrança de consulta do DynamoDB depende dos bytes examinados, então mostramos uma faixa de sensibilidade em vez de fingir conhecer sua travessia:
| Corpus | Armazenamento DynamoDB | Consultas DynamoDB (4 / 40 / 400 MB examinados) | Armazenamento S3 Vectors | Consultas S3 Vectors |
|---|---|---|---|---|
| 1M vetores | ~$1.95 | $8 / $80 / $800 | ~$0.23 | ~$11 |
| 10M vetores | ~$19.50 | $8 / $80 / $800 | ~$2.35 | ~$80 |
| 100M vetores | ~$195 | $8 / $80 / $800 | ~$23.50 | ~$217 |
Duas coisas saem dessa tabela. O custo por consulta do DynamoDB não cresce com o tamanho do corpus — uma pesquisa ANN examina uma vizinhança, não o índice, e o escopo por chave de partição a encolhe ainda mais.
A vantagem de armazenamento do S3 Vectors (~8×, já que o DynamoDB armazena duas cópias f32 a 4× a taxa) se acumula para sempre, com ou sem consultas.
Quando usar cada um
- Vetores descrevem itens vivos que você já mantém no DynamoDB (tickets, produtos, sessões de usuário, memória de agente): use o índice vetorial. Um caminho de gravação, um item, nenhum pipeline de sincronização para desviar.
- Milhões de embeddings, consultados ocasionalmente (RAG sobre documentos, arquivos históricos, jobs noturnos): use o S3 Vectors. Carregue em lote de forma barata, pague $0.06/GB em repouso, tolere algumas centenas de ms.
- QPS alto com ranqueamento híbrido (relevância textual + vetores, facetas, agregações): o OpenSearch continua sendo a resposta, com um piso de infraestrutura de cerca de $350/mês para uma coleção serverless clássica.
- Vetores unidos a dados relacionais: Aurora PostgreSQL com pgvector, que escala a zero e fica abaixo de ~$50/mês para cargas RAG pequenas.
O padrão honesto para uma casa DynamoDB é usar os dois. Mantenha os vetores quentes e filtráveis na tabela, onde as gravações são atômicas com o item, e arquive a cauda longa no S3 Vectors, cujas gravações em lote fortemente consistentes fazem dele um destino limpo.
As armadilhas
- Desindexação silenciosa: um item sem o atributo
HASHdo índice grava na tabela normalmente e nunca entra no índice vetorial. Reproduzimos isso ao vivo: oPutItemteve sucesso, e o vetor estava ausente de todas as partições 15 segundos depois. Nenhum erro, nenhum resultado, nada na resposta para avisar você. - Gravações com a dimensão errada são rejeitadas: troque de modelo de embedding sem migrar e toda gravação falha com uma
ValidationExceptionque nomeia o atributo e os dois tamanhos (Invalid size for parameter, capturada literalmente na própria página dela), já que o índice fixa a contagem de dimensões para sempre. - Embeddings obsoletos: o DynamoDB nunca recalcula vetores. Edite o texto de um ticket sem regravar
embeddinge as pesquisas casam silenciosamente com o conteúdo antigo. Streams mais um consumidor de regeneração é a correção padrão. TopKsempre retorna K itens: com três boas correspondências e--top-k 10, você ainda recebe 10. Julgue a relevância peloScore, não pela contagem de resultados, e lembre que a direção da pontuação se inverte entre as funções de distância.- Os mínimos de 1 KB: vetores de baixa dimensão não são medidos proporcionalmente mais baratos, nem em gravações nem em pesquisas.
- Tudo é imutável: dimensões, função de distância e o conjunto de atributos de uma projeção
INCLUDEexigem excluir e recriar para mudar. O armazenamento do índice fatura durante toda a vida do índice, consultado ou não.
Experimente com suas próprias tabelas
A pesquisa vetorial herda a disciplina de custo que o resto do DynamoDB ensinou a você. Dimensione o embedding antes de se comprometer com ele, porque os limites de tamanho de item ainda se aplicam e um embedding de 3072 dimensões adiciona 12 KB a cada gravação de item em ambos os medidores.
A mecânica do índice parecerá familiar se você sabe como os GSIs replicam de forma assíncrona e quando escolher um GSI em vez de um LSI. Para busca lexical sobre os mesmos dados, o DynamoDB continua sem um motor de texto completo; a pesquisa vetorial casa significado em vez de grafia.
Verifique o custo real em bytes de um embedding na calculadora de tamanho de item, depois experimente o DynoTable para navegar pelos itens por trás do seu índice vetorial — embeddings aparecem como atributos de lista comuns bem ao lado dos campos que você usa para filtrar.