Was this page helpful?
Caution
You're viewing documentation for an unstable version of ScyllaDB Manual. Switch to the latest stable version.
Alternator Vector Search¶
Introduction¶
Alternator vector search is a ScyllaDB extension to the DynamoDB-compatible API that enables approximate nearest neighbor (ANN) search on numeric vectors stored as item attributes.
In a typical use case, each item in a table contains a high-dimensional embedding vector (e.g., produced by a machine-learning model), and a query asks for the k items whose stored vectors are closest to a given query vector. This kind of similarity search is a building block for recommendation engines, semantic text search, image retrieval, and other AI/ML workloads.
Because this feature does not exist in Amazon DynamoDB, all applications that use it must be written specifically for Alternator.
For a broader introduction to Vector Search concepts and terminology, see the Vector Search Concepts and Vector Search Glossary sections of the ScyllaDB Cloud documentation.
Overview¶
The workflow has three steps:
Create a table (or update an existing one) with one or more vector indexes.
Write items that include the indexed vector attribute, just like any other list attribute.
Query using the
VectorSearchparameter to retrieve the k nearest neighbors.
API extensions¶
CreateTable — VectorIndexes parameter¶
A new optional parameter VectorIndexes can be passed to CreateTable.
It is a list of vector index definitions, each specifying:
Field |
Type |
Description |
|---|---|---|
|
String |
Unique name for this vector index. Follows the same naming rules as table names: 3–192 characters, matching the regex |
|
Structure |
Describes the attribute to index (see below). |
|
Structure |
Optional. Specifies which attributes are projected into the vector index (see below). |
VectorAttribute fields:
Field |
Type |
Description |
|---|---|---|
|
String |
The item attribute that holds the vector. It must not be a key column. |
|
Integer |
The fixed size of the vector (number of elements). |
Projection fields:
The optional Projection parameter is identical to the one used for DynamoDB
GSI and LSI, and specifies which attributes are stored in the vector index and
returned when Select=ALL_PROJECTED_ATTRIBUTES is used in a vector search query:
|
Description |
|---|---|
|
Only the primary key attributes of the base table (hash key and range key if present) are projected into the index. This is the default when |
|
All table attributes are projected into the index. (Not yet supported.) |
|
The primary key attributes plus the additional non-key attributes listed in |
Note: Currently only
ProjectionType=KEYS_ONLYis implemented. SpecifyingProjectionType=ALLorProjectionType=INCLUDEreturns aValidationException. SinceKEYS_ONLYis also the default, omittingProjectionentirely is equivalent to specifying{'ProjectionType': 'KEYS_ONLY'}.
Example (using boto3):
table = dynamodb.create_table(
TableName='my-table',
KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}],
AttributeDefinitions=[{'AttributeName': 'id', 'AttributeType': 'S'}],
BillingMode='PAY_PER_REQUEST',
VectorIndexes=[
{
'IndexName': 'embedding-index',
'VectorAttribute': {'AttributeName': 'embedding', 'Dimensions': 1536},
}
],
)
Constraints:
A vector index may not share a name with another vector index, a GSI, or an LSI on the same table.
The target attribute must not be a key column or an index key column.
Dimensionsmust be a positive integer up to the implementation maximum.Vector indexes require ScyllaDB to operate with tablets (not vnodes).
Multiple vector indexes can be created on the same table in a single
CreateTablecall.
UpdateTable — VectorIndexUpdates parameter¶
A new optional parameter VectorIndexUpdates can be passed to UpdateTable
to add or remove a vector index after the table is created. At most one
index operation (Create or Delete) may be requested per call.
Each element of the list is an object with exactly one of the following keys:
Create:
{
"Create": {
"IndexName": "my-vector-index",
"VectorAttribute": {"AttributeName": "embedding", "Dimensions": 1536},
"Projection": {"ProjectionType": "KEYS_ONLY"}
}
}
The Projection field in the Create action is optional and accepts the same
values as the Projection field in CreateTable’s VectorIndexes (see above).
Currently only ProjectionType=KEYS_ONLY is supported; it is also the default
when Projection is omitted.
Delete:
{
"Delete": {
"IndexName": "my-vector-index"
}
}
The same constraints as CreateTable’s VectorIndexes apply.
DescribeTable — VectorIndexes in the response¶
DescribeTable (and CreateTable’s response) returns a VectorIndexes
field in the TableDescription object when the table has at least one
vector index. The structure mirrors the CreateTable input: a list of
objects each containing IndexName, VectorAttribute
(AttributeName + Dimensions), and Projection (ProjectionType).
Currently Projection always contains {"ProjectionType": "KEYS_ONLY"}
because that is the only supported projection type.
Each vector index entry also includes status fields that mirror the standard
behavior of GlobalSecondaryIndexes in DynamoDB:
Field |
Type |
Description |
|---|---|---|
|
String |
|
|
Boolean |
Present and |
When creating a vector index on a non-empty table (via UpdateTable), data
already in the table is picked up by the vector store through a full-table
scan (backfill). During this period IndexStatus will be "CREATING" and
Backfilling will be true. Once the scan completes the vector store
transitions to monitoring CDC for ongoing changes, and IndexStatus becomes
"ACTIVE".
Type enforcement before and after index creation differs:
Pre-existing items: when the backfill scan encounters an item whose indexed attribute is not a list of exactly the right number of numbers (e.g., it is a string, a list of the wrong length, or contains non-numeric elements), that item is silently skipped and not indexed. The item remains in the base table unchanged.
New writes once the index exists: any attempt to write a value to the indexed attribute that is not a list of exactly
Dimensionsnumbers — where each number is representable as a 32-bit float — is rejected with aValidationException. This applies toPutItem,UpdateItem, andBatchWriteItem. A missing value for the indexed attribute is always allowed; such items simply are not indexed.
Important: Applications must wait until
IndexStatusis"ACTIVE"before issuingQueryrequests against a vector index. Queries on a vector index whoseIndexStatusis still"CREATING"may fail. This applies both when adding a vector index to an existing table viaUpdateTableand when creating a new table with aVectorIndexesparameter inCreateTable— even though the new table starts empty, the vector store still needs a short initialization period before it can serve queries.
Query — VectorSearch parameter¶
To perform a nearest-neighbor search, pass the VectorSearch parameter
to Query. When this parameter is present the request is interpreted as a
vector search rather than a standard key-condition query.
VectorSearch fields:
Field |
Type |
Description |
|---|---|---|
|
AttributeValue (list |
The query vector as a DynamoDB |
Example:
response = table.query(
IndexName='embedding-index',
Limit=10,
VectorSearch={
'QueryVector': {'L': [{'N': '0.1'}, {'N': '-0.3'}, {'N': '0.7'}, ...]},
},
)
Requirements:
Parameter |
Details |
|---|---|
|
Required. Must name a vector index on this table (not a GSI or LSI). |
|
Required. A DynamoDB |
QueryVector length |
Must match the |
|
Required. Defines k — how many nearest neighbors to return. Must be a positive integer. |
Differences from standard Query:
Vector search reinterprets several standard Query parameters in a fundamentally
different way, and explicitly rejects others that have no meaningful interpretation:
Limitmeans top-k, not page size. In a standard Query,Limitcaps the number of items examined per page, and you page through results withExclusiveStartKey. In vector search,Limitdefines k: the ANN algorithm runs once and returns exactly the k nearest neighbors. There is no natural “next page” — each page would require a full re-run of the search — soExclusiveStartKeyis rejected.Results are ordered by vector distance, not by sort key. A standard Query returns rows in sort-key order;
ScanIndexForward=falsereverses that order. Vector search always returns results ordered by their distance toQueryVector(nearest first). HavingScanIndexForwardspecify sort-key direction has no meaning here, soScanIndexForwardis rejected.Eventual consistency only. The vector store is an external service fed asynchronously from ScyllaDB via CDC. Like GSIs, vector indexes can never reflect writes instantly, so strongly-consistent reads are impossible.
ConsistentRead=trueis rejected.No key condition. A standard Query requires a
KeyConditionExpressionto select which partition to read. Vector search queries the vector store globally across all partitions of the table.KeyConditionsandKeyConditionExpressionare therefore not applicable and are silently ignored. (Local vector indexes, which would scope the search to a single partition and useKeyConditionExpression, are not yet supported.)
Select parameter:
The standard DynamoDB Select parameter is supported for vector search queries
and controls which attributes are returned for each matching item:
|
Behavior |
|---|---|
|
Return only the attributes projected to the vector index. Currently, only the primary key attributes (hash key, and range key if present) are projected; support for configuring additional projected attributes is not yet implemented. Note that the vector attribute itself is not included: the vector store may not retain the original floating-point values (e.g., it may quantize them), so the authoritative copy lives only in the base table. This is the most efficient option because Scylla can return the results directly from the vector store without an additional fetch from the base table. |
|
Return all attributes of each matching item, fetched from the base table. |
|
Return only the attributes named in |
|
Return only the count of matching items; no |
When neither Select nor ProjectionExpression/AttributesToGet is specified,
Select defaults to ALL_PROJECTED_ATTRIBUTES. When ProjectionExpression or
AttributesToGet is present without an explicit Select, it implies
SPECIFIC_ATTRIBUTES. Using ProjectionExpression or AttributesToGet
together with an explicit Select other than SPECIFIC_ATTRIBUTES is an error.
Note on performance: Unlike a DynamoDB LSI, a vector index allows you to
read non-projected attributes (e.g., with ALL_ATTRIBUTES or
SPECIFIC_ATTRIBUTES requesting a non-key column). However, doing so requires
an additional read from the base table for each result — similar to reading
through a secondary index (rather than a materialized view) in CQL — and is
therefore significantly slower than returning only projected attributes with
ALL_PROJECTED_ATTRIBUTES. For latency-sensitive applications, prefer
ALL_PROJECTED_ATTRIBUTES or limiting SPECIFIC_ATTRIBUTES to key columns.
FilterExpression:
Vector search supports FilterExpression for post-filtering results. This
works the same way as FilterExpression on a standard DynamoDB Query: after
the ANN search, the filter is applied to each candidate item and only matching
items are returned.
Important: filtering happens after the Limit nearest neighbors have
already been selected by the vector index. If the filter discards some of
those candidates, the response may contain fewer than Limit items. The
server does not automatically fetch additional neighbors to replace filtered-out
items. This is identical to how FilterExpression interacts with Limit in a
standard DynamoDB Query.
The response always includes two count fields:
Field |
Description |
|---|---|
|
The number of candidates returned by the vector index (always equal to |
|
The number of items that passed the |
Interaction with Select:
Select=ALL_ATTRIBUTES: Each candidate item is fetched from the base table, the filter is evaluated against all its attributes, and only matching items are returned.Countreflects the number of items that passed the filter.Select=SPECIFIC_ATTRIBUTES: Each candidate item is fetched from the base table — including any attributes needed by the filter expression, even if those attributes are not listed inProjectionExpression— and the filter is applied. Only the projected attributes are returned in the response; filter attributes that were not requested are not included in the returned items.Select=COUNT: The candidate items are still fetched from the base table and the filter is evaluated for each one, but noItemslist is returned.Countreflects the number of items that passed the filter;ScannedCountis the total number of candidates examined. This is useful for counting matches without transferring item data to the client.Select=ALL_PROJECTED_ATTRIBUTES(default): When no filter is present this is the most efficient mode — results are returned directly from the vector store without any base-table reads. When aFilterExpressionis present, however, the full item must be fetched from the base table to evaluate the filter, and only the projected (key) attributes are returned for items that pass.
Note:
QueryFilter(the legacy non-expression filter API) is not supported for vector search queries and will be rejected with aValidationException. UseFilterExpressioninstead.