View a markdown version of this page

Tutorial: sua primeira pesquisa vetorial - Amazon DynamoDB

Tutorial: sua primeira pesquisa vetorial

Imagine um catálogo de produtos em que os compradores descrevam o que desejam com suas próprias palavras, em vez de corresponder às palavras-chave exatas. Você pode armazenar uma incorporação vetorial da descrição de cada produto no DynamoDB e, em seguida, consultar um índice vetorial para encontrar as correspondências mais próximas.

Este tutorial cria uma tabela com um índice vetorial, gera incorporações de 1024 dimensões com o Amazon Bedrock Titan Text Embeddings V2, carrega 50 produtos e executa uma pesquisa por similaridade que retorna as cinco correspondências mais próximas. Cada comando pode ser colado diretamente em um terminal. Para obter informações sobre como as incorporações funcionam com o DynamoDB, consulte Geração de incorporações vetoriais.

Sobre escala e recall

Um índice vetorial de produção contém de milhões a bilhões de vetores. Os índices vetoriais usam a pesquisa aproximada do vizinho mais próximo, e as características de recall dessa abordagem se tornam observáveis apenas em uma escala muito maior. Trate o catálogo de 50 itens aqui como uma demonstração da mecânica. Para obter orientação sobre dimensionamento e ajuste, consulte Práticas recomendadas para índices vetoriais.

Pré-requisitos

Antes de começar, você deve ter o seguinte:

  • AWS CLI versão 2.36.16 ou posterior O suporte ao índice vetorial foi adicionado à AWS CLI e aos SDKs da AWS na atualização do modelo de serviço lançada em 4 de agosto de 2026. As versões anteriores não reconhecem o parâmetro --vector-indexes ou o comando search-vectors. Verifique sua versão com aws --version e atualize, se necessário. Se você usar um SDK da AWS em vez da AWS CLI, precisará do botocore versão 1.43.64 ou posterior, ou da versão equivalente do SDK do seu idioma.

  • Credenciais com permissões para as ações CreateTable, DescribeTable, PutItem, BatchWriteItem, Scan, SearchVectors, UpdateTable e DeleteTable do DynamoDB e para a ação InvokeModel do Amazon Bedrock. dynamodb:SearchVectors é uma ação nova e, portanto, as políticas existentes que concedem acesso de leitura ao DynamoDB não a incluem.

  • Acesso ao modelo Titan Text Embeddings V2 habilitado no Amazon Bedrock para sua conta e região. O acesso ao modelo do Amazon Bedrock é concedido por conta e por região. Assim, você deve habilitar o modelo antes de poder chamá-lo.

  • jq instalado para gerar novamente a saída do modelo no formato do DynamoDB.

  • Uma região em que os índices vetoriais do DynamoDB e o Amazon Bedrock Titan Text Embeddings V2 estão disponíveis. Como a disponibilidade do modelo do Amazon Bedrock varia de acordo com a região e geralmente é mais restrita do que a cobertura regional do DynamoDB, confirme os dois antes de escolher uma região. Para saber mais sobre a disponibilidade de modelos do Amazon Bedrock, consulte Suporte ao modelo por região da AWS no Guia do usuário do Amazon Bedrock.

Cobranças

Este tutorial gera cobranças pelas invocações do modelo do Amazon Bedrock e pelo armazenamento do DynamoDB. Ele faz 51 chamadas de incorporação, cada uma cobrada como uma solicitação de inferência do Amazon Bedrock, em entradas curtas de uma única frase. As cobranças de armazenamento do DynamoDB serão aplicadas enquanto a tabela e o índice vetorial existirem.

Confirme qual região você está usando

Cada comando deste tutorial deve ser executado na mesma região. Confirme a região que a AWS CLI usará antes de começar, porque AWS_REGION tem precedência sobre AWS_DEFAULT_REGION, e ambos têm precedência sobre a configuração de region no arquivo de configuração da AWS CLI. Um valor AWS_REGION disperso no shell cria a tabela em algum lugar diferente da região pretendida, e o modelo do Amazon Bedrock pode não estar habilitado lá. Para eliminar todas as dúvidas, transmita --region region explicitamente em cada comando.

SearchVectors usa um endpoint separado

SearchVectors é resolvido para um endpoint de pesquisa dedicado em vez do endpoint padrão do DynamoDB. Em uma região comercial, as solicitações vão para search-dynamodb.region.amazonaws.com, enquanto todas as outras operações neste tutorial vão para dynamodb.region.amazonaws.com. As variantes de FIPS e pilha dupla seguem o mesmo padrão. Isso tem duas consequências:

  • Se a sua rede restringir o tráfego de saída por meio de um endpoint da VPC, proxy ou lista de permissões de saída, você também deverá permitir o nome do host de pesquisa. Caso contrário, CreateTable e as operações de gravação serão bem-sucedidas e somente SearchVectors falhará, normalmente com um erro de conexão que não indica a causa.

  • Não use --endpoint-url para substituir o endpoint do DynamoDB nesses comandos. Uma única substituição não pode servir aos dois nomes de host e interromperá o roteamento da pesquisa.

  1. Crie uma tabela com um índice vetorial. Isso cria uma tabela Products com um índice vetorial chamado DescriptionIndex no atributo DescriptionVector. O índice usa a função de distância COSINE com 1024 dimensões para corresponder à saída do Titan Text Embeddings V2. Como nenhuma chave de partição de índice vetorial está definida, você não precisa de uma SearchConditionExpression para pesquisar.

    aws dynamodb create-table \ --table-name Products \ --attribute-definitions AttributeName=ProductId,AttributeType=S \ --key-schema AttributeName=ProductId,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --vector-indexes \ "[ { \"IndexName\": \"DescriptionIndex\", \"VectorAttribute\": {\"AttributeName\": \"DescriptionVector\"}, \"Projection\": {\"ProjectionType\": \"ALL\"}, \"Dimensions\": 1024, \"DistanceFunction\": \"COSINE\" } ]"

    Este exemplo usa ProjectionType de ALL para que todos os atributos estejam disponíveis para os resultados da pesquisa. Se você usar INCLUDE, o orçamento projetado de atributos não essenciais será compartilhado: o atributo vetorial conta como um atributo e cada elemento do esquema de pesquisa INLINE_FILTER conta como um. Os elementos do esquema de pesquisa HASH não contam para o limite.

  2. Aguarde o índice se tornar ativo. Execute até que IndexStatus seja ACTIVE.

    aws dynamodb describe-table \ --table-name Products \ --query 'Table.VectorIndexes[0].[IndexName,IndexStatus,Backfilling]'

    Para um índice criado como parte de CreateTable, como neste tutorial, Backfilling não é relatado e o comando retorna null. Use IndexStatus sozinho como sinal nesse caso.

    Backfilling é relatado para um índice vetorial que você adiciona a uma tabela existente com UpdateTable. Nesse caso, espere até que IndexStatus seja ACTIVE e Backfilling seja false antes de confiar nos resultados completos da pesquisa.

    Espere pelo índice, não apenas pela tabela

    Não use aws dynamodb wait table-exists para bloquear a pesquisa. Esse waiter corresponde a Table.TableStatus, que se torna ACTIVE enquanto o índice vetorial ainda pode ser CREATING. Como não há waiter para a disponibilidade do índice vetorial, faça a pesquisa DescribeTable conforme mostrado. Pesquisar um índice que ainda não está ACTIVE falha, e pesquisar durante o preenchimento pode retornar resultados incompletos.

    Pelo mesmo motivo, você não pode excluir a tabela até que cada índice vetorial tenha terminado de ser criado. DeleteTable retorna ResourceInUseException com a mensagem "Não é possível excluir a tabela enquanto os índices estão sendo criados, atualizados ou excluídos".

  3. Crie o catálogo de produtos. Salve os 50 produtos a seguir em um arquivo separado por tabulação chamado products.tsv. Cada linha contém um ID do produto, um nome e uma frase de descrição. O catálogo contém dez grupos de cinco produtos relacionados, o que facilita a interpretação dos resultados da pesquisa na última etapa.

    p01 Insulated Travel Mug A vacuum insulated stainless steel mug that keeps hot drinks warm for up to twelve hours. p02 Stovetop Espresso Maker A compact aluminum pot that brews strong espresso style coffee directly on a gas or electric burner. p03 Manual Burr Coffee Grinder A hand cranked grinder with adjustable ceramic burrs for consistent coffee grounds. p04 Pour Over Coffee Dripper A ceramic cone that sits on a mug and brews a single cup of filter coffee. p05 Electric Milk Frother A handheld battery powered whisk that creates dense foam for lattes and cappuccinos. p06 Lightweight Running Shoe A breathable mesh road shoe with cushioned foam midsole for daily training runs. p07 Trail Running Shoe An aggressive lugged outsole shoe built for grip on loose gravel and muddy trails. p08 Moisture Wicking Running Socks Ankle height socks knitted from synthetic yarn that pulls sweat away from the skin. p09 Reflective Running Vest A lightweight vest with high visibility strips for running safely after dark. p10 Hydration Waist Belt An elastic belt that holds two small water flasks and a phone during long runs. p11 Ergonomic Mesh Office Chair An adjustable desk chair with breathable mesh back and lumbar support for long work sessions. p12 Sit Stand Desk Converter A height adjustable platform that raises a monitor and keyboard for standing work. p13 Monitor Arm Mount A clamp mounted articulating arm that lifts a display off the desk surface. p14 Under Desk Footrest An angled cushioned platform that supports the feet and improves seated posture. p15 Wireless Split Keyboard A two piece keyboard that separates for a natural shoulder width typing position. p16 Noise Cancelling Headphones Over ear wireless headphones that actively silence engine noise on long flights. p17 Wireless Earbuds Compact in ear buds with a charging case and multi hour battery for commuting. p18 Portable Bluetooth Speaker A water resistant rechargeable speaker sized to fit in a backpack side pocket. p19 Studio Monitor Headphones Wired closed back headphones with flat frequency response for audio mixing. p20 Wired Lapel Microphone A small clip on microphone for recording clear speech during interviews. p21 Four Season Backpacking Tent A double wall tent with an aluminum pole set rated for wind and heavy rain. p22 Down Sleeping Bag A mummy shaped bag filled with compressible down insulation for cold weather camping. p23 Inflatable Sleeping Pad A lightweight pad that inflates in a few breaths and packs down to bottle size. p24 Canister Camping Stove A screw on burner that boils water quickly using a compact fuel canister. p25 Rechargeable Camp Lantern A collapsible lantern with adjustable brightness and a built in battery. p26 Cast Iron Skillet A preseasoned heavy pan that holds heat evenly for searing and oven baking. p27 Nonstick Frying Pan A coated aluminum pan that releases eggs and fish without added oil. p28 Stainless Steel Stock Pot A tall wide pot for boiling pasta and simmering large batches of soup. p29 Enameled Dutch Oven A heavy lidded pot that moves from stovetop to oven for slow braising. p30 Bamboo Cutting Board A large reversible board with a juice groove around the edge. p31 Padded Laptop Backpack A water resistant pack with a suspended sleeve that protects a fifteen inch laptop. p32 Slim Laptop Sleeve A close fitting neoprene case that shields a notebook inside a larger bag. p33 Rolling Carry On Suitcase A hard shell four wheel case sized to fit most overhead cabin bins. p34 Packing Cube Set Zippered fabric cubes that compress clothing and organize a suitcase. p35 Leather Messenger Bag A single strap shoulder bag with a padded compartment and interior pockets. p36 Daily Facial Moisturizer A light lotion with humectants that hydrates skin without leaving residue. p37 Mineral Sunscreen Lotion A broad spectrum zinc based sunscreen formulated for sensitive facial skin. p38 Gentle Foaming Cleanser A low pH face wash that removes oil and sunscreen without stripping the skin. p39 Vitamin C Serum A brightening serum applied before moisturizer to even skin tone over time. p40 Overnight Repair Cream A rich night cream with ceramides that restores the skin barrier while sleeping. p41 Stainless Steel Dog Bowl A weighted nonslip bowl that resists tipping during enthusiastic feeding. p42 Padded Dog Harness An adjustable chest harness that distributes pull away from the neck on walks. p43 Retractable Dog Leash A spring loaded leash that extends and locks at several walking lengths. p44 Interactive Cat Puzzle Feeder A slow feed tray that makes a cat work for dry food and eat more slowly. p45 Self Cleaning Litter Box An enclosed box with a raking mechanism that sifts waste after each use. p46 Bypass Pruning Shears Sharp hardened blades that make clean cuts on green stems and small branches. p47 Long Handled Garden Spade A steel bladed spade with a wooden shaft for turning soil and digging beds. p48 Adjustable Hose Spray Nozzle A metal nozzle that shifts from a fine mist to a strong jet stream. p49 Raised Garden Bed Kit Interlocking cedar panels that assemble into an elevated planting box. p50 Drip Irrigation Starter Kit Tubing and emitters that deliver water slowly to the base of each plant.

    O separador entre os três campos deve ser um caractere de tabulação literal. Se você copiar o catálogo de um navegador, verifique se as tabulações sobreviveram antes de continuar.

  4. Gere uma incorporação para um produto. Execute primeiro uma única chamada de incorporação para confirmar se o acesso ao modelo do Amazon Bedrock funciona. O campo inputText contém o texto a ser incorporado, dimensions define o tamanho da saída (os valores válidos são 256, 512 ou 1024) e normalize produz vetores de comprimento unitário, o que é recomendado para pesquisa por similaridade de cosseno.

    mkdir -p emb aws bedrock-runtime invoke-model \ --model-id amazon.titan-embed-text-v2:0 \ --body '{"inputText":"A vacuum insulated stainless steel mug that keeps hot drinks warm for up to twelve hours.","dimensions":1024,"normalize":true}' \ --cli-binary-format raw-in-base64-out \ --content-type application/json \ --accept application/json \ emb/p01.json

    O sinalizador --cli-binary-format raw-in-base64-out é obrigatório. O padrão da AWS CLI v2 é a codificação base64 para parâmetros binários, portanto, sem esse sinalizador, o corpo JSON bruto não é enviado corretamente. A resposta é gravada em emb/p01.json e contém uma matriz embedding de 1024 números de ponto flutuante. Confirme a contagem de dimensões.

    jq '.embedding | length' emb/p01.json

    O resultado é 1024.

  5. Grave o primeiro produto. Transforme a incorporação no formato de item do DynamoDB e grave-a. O atributo vetorial armazenado usa o tipo L (lista) do DynamoDB agrupando cada número em um tipo N.

    jq '{"ProductId":{"S":"p01"},"Title":{"S":"Insulated Travel Mug"},"DescriptionVector":{"L":[.embedding[]|{"N":(.|tostring)}]}}' emb/p01.json > item-p01.json aws dynamodb put-item --table-name Products --item file://item-p01.json
    Tamanho do vetor e limites de itens

    Um vetor de 1024 dimensões adiciona aproximadamente 32 KB à carga útil da solicitação e cerca de 5 KB ao item armazenado, bem dentro do limite de tamanho de item de 400 KB do DynamoDB. A contagem de dimensões é o principal fator do tamanho do item quando você armazena incorporações.

  6. Incorpore os produtos restantes. Esse loop gera uma incorporação para cada produto restante. Ele ignora qualquer arquivo que já exista, para que você possa executá-lo novamente com segurança se uma chamada falhar.

    while IFS=$'\t' read -r id title description; do [ -s "emb/$id.json" ] && continue body=$(jq -n --arg t "$description" '{inputText:$t,dimensions:1024,normalize:true}') aws bedrock-runtime invoke-model \ --model-id amazon.titan-embed-text-v2:0 \ --body "$body" \ --cli-binary-format raw-in-base64-out \ --content-type application/json \ --accept application/json \ "emb/$id.json" >/dev/null || echo "FAILED $id" done < products.tsv ls emb/*.json | wc -l

    A contagem deve ser 50 antes de você continuar. Se alguma chamada mostrar FAILED, execute o loop novamente; ele tentará novamente somente os arquivos ausentes.

    Cotas de taxa do InvokeModel

    O Amazon Bedrock aplica cotas de taxa de solicitação ao InvokeModel. Se você modificar esse loop para emitir chamadas em paralelo, espere exceções de controle de utilização em algumas chamadas e sempre verifique a contagem final de arquivos em vez de presumir que todas as chamadas foram bem-sucedidas. Um catálogo parcialmente incorporado é carregado sem erros e produz resultados de pesquisa que omitem silenciosamente os produtos ausentes.

  7. Carregue os produtos restantes. Crie carga úteis de solicitação de 25 itens cada, que é o máximo aceito por BatchWriteItem.

    batch=0 count=0 echo -n '{"Products":[' > batch-0.json while IFS=$'\t' read -r id title description; do if [ "$count" -eq 25 ]; then echo ']}' >> "batch-$batch.json" batch=$((batch+1)); count=0 echo -n '{"Products":[' > "batch-$batch.json" fi [ "$count" -gt 0 ] && echo -n ',' >> "batch-$batch.json" jq -c --arg id "$id" --arg title "$title" \ '{PutRequest:{Item:{ProductId:{S:$id},Title:{S:$title}, DescriptionVector:{L:[.embedding[]|{"N":(.|tostring)}]}}}}' \ "emb/$id.json" >> "batch-$batch.json" count=$((count+1)) done < <(tail -n +2 products.tsv) echo ']}' >> "batch-$batch.json"

    O loop lê de um redirecionamento em vez de um pipe porque um loop while com pipe é executado em um subshell em alguns shells, o que descarta os valores batch e count e produz arquivos em lote malformados.

    Envie cada lote. BatchWriteItem pode ser parcialmente bem-sucedido, portanto, reenvie tudo o que for retornado em UnprocessedItems.

    for f in batch-*.json; do cp "$f" pending.json for attempt in 1 2 3 4 5; do aws dynamodb batch-write-item \ --request-items file://pending.json \ --output json > resp.json left=$(jq '(.UnprocessedItems.Products // []) | length' resp.json) echo "$f attempt $attempt: unprocessed=$left" [ "$left" -eq 0 ] && break jq '.UnprocessedItems' resp.json > pending.json sleep 2 done done

    Confirme se todos os 50 itens estão presentes.

    aws dynamodb scan --table-name Products --select COUNT --query 'Count'
    As atualizações de ItemCount estão atrasadas

    Os valores ItemCount e IndexSizeBytes relatados por DescribeTable para um índice vetorial são atualizados aproximadamente a cada seis horas. Assim, logo após o carregamento, eles ainda podem ser lidos como 0 mesmo que cada item tenha sido gravado. Use Scan com --select COUNT, conforme mostrado, para verificar uma carga. Não trate uma ItemCount zero como uma falha na carga.

  8. Gere uma incorporação de consulta e pesquise. Incorpore a frase de pesquisa com o mesmo modelo e contagem de dimensões que você usou para os itens armazenados.

    aws bedrock-runtime invoke-model \ --model-id amazon.titan-embed-text-v2:0 \ --body '{"inputText":"How can I make my desk more comfortable to work at","dimensions":1024,"normalize":true}' \ --cli-binary-format raw-in-base64-out \ --content-type application/json \ --accept application/json \ embedding-query.json
    O formato SearchVector difere do formato vetorial armazenado

    Ao armazenar um vetor em um atributo de item, você o envolve em um tipo L (lista): {"L":[{"N":"0.123"},...]}. Ao transmitir um vetor de consulta para SearchVectors, você usa uma matriz simples de valores N sem o wrapper L: [{"N":"0.123"},...]. A transformação jq a seguir é diferente da usada para os itens armazenados por esse motivo. Para obter mais informações, consulte Pesquisa básica.

    jq '[.embedding[]|{"N":(.|tostring)}]' embedding-query.json > query-vector.json aws dynamodb search-vectors \ --table-name Products \ --index-name DescriptionIndex \ --search-vector file://query-vector.json \ --top-k 5 \ --projection-expression "ProductId, Title" \ --return-consumed-capacity TOTAL

    O vetor de consulta e os vetores armazenados devem vir do mesmo modelo de incorporação e ter o mesmo número de dimensões. Usar um modelo ou uma contagem de dimensões diferente produz resultados sem sentido ou um erro de validação.

  9. Leia os resultados. O DynamoDB retorna resultados classificados por similaridade, com o item mais similar primeiro. Cada resultado contém os atributos Item projetados e uma Score.

    { "SearchResults": [ { "Item": { "ProductId": { "S": "p11" }, "Title": { "S": "Ergonomic Mesh Office Chair" } }, "Score": 0.6130197048187256 }, { "Item": { "ProductId": { "S": "p12" }, "Title": { "S": "Sit Stand Desk Converter" } }, "Score": 0.781868577003479 }, { "Item": { "ProductId": { "S": "p14" }, "Title": { "S": "Under Desk Footrest" } }, "Score": 0.816369354724884 }, { "Item": { "ProductId": { "S": "p13" }, "Title": { "S": "Monitor Arm Mount" } }, "Score": 0.8283305168151855 }, { "Item": { "ProductId": { "S": "p15" }, "Title": { "S": "Wireless Split Keyboard" } }, "Score": 0.8469693064689636 } ], "ConsumedCapacity": { "VectorSearchRequestBytes": 31449.0 } }

    As pontuações dependem do modelo de incorporação e do texto de entrada exato, portanto, seus valores serão ligeiramente diferentes. O que importa é quais itens foram selecionados e em que ordem. A consulta não continha as palavras cadeira, monitor ou teclado, mas a pesquisa retornou os cinco produtos de mesa e escritório antes dos outros 45 itens do catálogo. Nada de café, acampamento ou grupos de animais de estimação aparecer.

    Tente fazer outras consultas para ver o mesmo comportamento com grupos diferentes. Repita a etapa anterior com "Something to brew fresh coffee at home" e os principais resultados são a máquina de café expresso, o gotejador de água e o batedor de leite. Repita com "Keeping my dog safe on walks" e a coleira e o arnês virão primeiro, seguidos por itens que estão apenas vagamente relacionados, porque o catálogo contém apenas dois produtos muito parecidos. Esse último caso é digno de nota: a pesquisa sempre retorna o número de itens que você pede, mesmo quando o catálogo não contém tantas correspondências boas. Use os valores de Score, não a contagem de resultados, para avaliar a qualidade da correspondência.

    A forma de ler uma pontuação depende da função de distância que o índice usa:

    • COSINE e EUCLIDEAN retornam os itens com as menores pontuações, portanto, quanto menor, mais semelhante. As pontuações do cosseno variam de 0 para direção idêntica a 2 para direção oposta.

    • DOT_PRODUCT retorna os itens com as pontuações mais altas, portanto, quanto maior, mais semelhante.

    Como esse índice usa COSINE, o primeiro resultado tem a pontuação mais baixa. Pesquisar com texto idêntico a uma descrição armazenada retorna esse item primeiro com uma pontuação igual ou próxima de zero.

Fazer a limpeza.

Para evitar cobranças contínuas, exclua os recursos que você criou neste tutorial. O armazenamento do índice vetorial será cobrado enquanto o índice existir, independentemente de você realizar pesquisas nele ou não.

Para excluir o índice vetorial, mas manter a tabela Products e os itens, use UpdateTable. Os itens permanecem na tabela e somente o índice é removido.

aws dynamodb update-table \ --table-name Products \ --vector-index-updates \ "[ {\"Delete\": {\"IndexName\": \"DescriptionIndex\"}} ]"

Para excluir a tabela e o índice vetorial juntos, exclua a tabela.

aws dynamodb delete-table --table-name Products

Confirme se a tabela foi excluída. O comando a seguir retorna uma ResourceNotFoundException quando a exclusão é concluída.

aws dynamodb describe-table --table-name Products

Para obter mais informações sobre como remover um índice vetorial de uma tabela que você deseja manter, consulte Excluir um índice de vetores.

Próximas etapas

Depois de concluir essa pesquisa vetorial básica, explore esses tópicos relacionados.