Writing vectors is half the story. The payoff is the query: given a question, find the stored vectors that mean something similar. In S3 Vectors that is one operation, query_vectors, and this page covers how to shape it well - choosing topK, reading distances correctly for your metric, and filtering on metadata so search stays both fast and relevant.
The similarity-search calls are a new 2026 surface, so where a name might still move there is a short verify-at-build-time note. Embedding generation uses the stable Bedrock invoke_model API.
The metric is fixed when you create the index, and it defines the ranking:
cosine measures the angle between vectors, ignoring magnitude. It is the common default for text embeddings (Titan, Cohere) because meaning is encoded in direction. Smaller cosine distance means more similar.
euclidean measures straight-line distance and does respond to magnitude. Some non-text models recommend it.
You cannot change a metric after creation - to switch, create a new index and re-load. Always embed queries with the same model that produced the stored vectors; mixing models or dimensions makes distances meaningless.
topK is how many neighbors come back. For RAG, a small value (3 to 10) usually feeds the LLM enough context without drowning it in weak matches. Larger values cost more and dilute relevance. If you plan to re-rank results with a second model, retrieve a slightly larger set (say 20) and trim after re-ranking.
A query can carry a filter document that restricts results to vectors whose metadata matches - for example, only a given tenant, language, or date range. This runs during search, so you get the top-k among the matching subset rather than filtering after the fact and coming up short.
# --- Python (boto3) ---res = sv.query_vectors( vectorBucketName="my-vectors", indexName="docs", topK=5, queryVector={"float32": q}, filter={"topic": "iam", "year": {"$gte": 2026}}, # verify operator syntax at build time returnMetadata=True, returnDistance=True,)# The filter grammar (equality vs range operators like $gte) is part of a 2026 API - confirm in current docs.
// --- TypeScript (AWS SDK v3) ---const res = await sv.send(new QueryVectorsCommand({ vectorBucketName: "my-vectors", indexName: "docs", topK: 5, queryVector: { float32: q }, filter: { topic: "iam", year: { $gte: 2026 } }, // verify operator syntax at build time returnMetadata: true, returnDistance: true,}));// The filter grammar (equality vs range operators like $gte) is part of a 2026 API - confirm in current docs.
For filtering to work well, declare the keys you filter on as filterable when you create the index (they are filterable by default unless listed under nonFilterableMetadataKeys). Keep bulky fields like the raw source text non-filterable so they do not bloat the filterable metadata.
Note that metadata filtering and returnMetadata=True require s3vectors:GetVectors in addition to s3vectors:QueryVectors.
Mismatched dimension - the query vector's length must equal the index dimension, or the call fails. Fix: embed queries with the same model that produced the stored vectors.
Wrong metric assumption - reading a euclidean distance as if it were cosine (or vice versa) leads to bad thresholds. Fix: know the index metric and calibrate thresholds against real data.
Expecting metadata without asking - metadata and distance are omitted unless you opt in. Fix: set returnMetadata=True and returnDistance=True, and grant s3vectors:GetVectors.
Filtering on non-filterable keys - keys marked nonFilterableMetadataKeys cannot be filtered. Fix: decide filterability at index creation; large fields stay non-filterable.
Treating distance as a fixed similarity score - absolute distances are not portable across models or metrics. Fix: tune any cutoff empirically for your index.
Zero or invalid vectors - all-zero vectors are rejected under cosine, and NaN/Infinity values are rejected. Fix: validate embeddings before querying or writing.
Start small - 3 to 10 for RAG. That gives the model enough context without weak matches. Retrieve more (around 20) only if a re-ranking step will trim the list afterward.
Cosine or euclidean?
Match your embedding model's recommendation. Cosine is the usual default for text embeddings like Titan and Cohere. The metric is fixed at index creation, so decide before you load data.
Why is metadata missing from my results?
Because returnMetadata defaults to false. Set it to true, and make sure your IAM policy includes s3vectors:GetVectors, which metadata access requires in addition to QueryVectors.
Can I filter results by metadata?
Yes, with a filter document on the query. It prunes during search so you get the true top-k of the matching subset. Confirm the exact filter operator grammar against current docs, as this is a 2026 API.
What does the distance number mean?
It is the metric's measure of dissimilarity - smaller is closer. Its scale depends on the metric and the model, so treat it as relative within one index rather than an absolute score.
Do I have to embed the query myself?
Yes. query_vectors takes a ready-made queryVector. Embed the query text with the same model and dimension used for the stored vectors, then pass the float array.
How do I page through more than the first results?
If the response includes a nextToken, pass it on the next query_vectors call to continue. Omit it when there are no more pages.
Why did my query fail with a dimension error?
The query vector length did not match the index dimension. Every vector - stored or query - must have exactly the dimension the index was created with.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+). Amazon S3 Vectors is a fast-moving 2026 API - verify exact operation and parameter names against current docs.
Reviewed by Chris St. John·Last updated Jul 23, 2026