Was this page helpful?
Vector and Text Search FAQ¶
Frequently asked questions about Vector and Text Search in ScyllaDB.
What similarity functions does ScyllaDB support?¶
ScyllaDB supports three similarity functions for vector indexes:
COSINE (default) — measures the angle between vectors. Best for normalized embeddings from text models.
DOT_PRODUCT — computes the inner product. Useful when vector magnitude carries meaning.
EUCLIDEAN — measures L2 (straight-line) distance. Best for spatial data.
See Choosing a Similarity Function for guidance on when to use each.
What is the maximum number of dimensions?¶
ScyllaDB supports vectors with dimensionality from 1 to 16,000. This is
compatible with all major embedding models, including OpenAI
(text-embedding-3-large at 3072 dimensions) and Cohere Embed.
How long until a new vector is searchable?¶
Newly inserted vectors are typically searchable within approximately 1 second (p50 latency), thanks to ScyllaDB’s fine-grained CDC reader. In the worst case, a change becomes visible within ~30 seconds (wide-framed CDC reader interval).
See Write-to-Query Latency for details.
Can I change the similarity function after creating an index?¶
No. Vector index options cannot be altered after creation. However, you can recreate the index with a new configuration.
Starting with ScyllaDB 2026.2, you can create a second vector index on the same column with the desired configuration. The old index continues serving queries while the new one is being built, and queries are automatically routed to the new index once it is ready. Then drop the old index:
CREATE CUSTOM INDEX IF NOT EXISTS my_index_v2
ON myapp.comments(comment_vector)
USING 'vector_index'
WITH OPTIONS = { 'similarity_function': 'DOT_PRODUCT' };
-- After the new index is ready:
DROP INDEX IF EXISTS my_index;
You must drop the existing index and recreate it with the new configuration. During the rebuild, similarity search is unavailable on the affected column:
DROP INDEX IF EXISTS my_index;
CREATE CUSTOM INDEX my_index ON myapp.comments(comment_vector)
USING 'vector_index'
WITH OPTIONS = { 'similarity_function': 'DOT_PRODUCT' };
The index will be rebuilt over the existing data when the new index is created.
For a zero-downtime migration procedure using a duplicate column, see Altering a Vector Index.
Does ScyllaDB support filtering in vector search queries?¶
Yes. ScyllaDB supports filtered vector search using two types of indexes:
Local (per-partition) vector indexes (recommended) — search only within a single partition’s index. This is the fastest approach. Design your schema so that columns you filter on are part of the partition key and use equality (
=) operators.Global vector indexes — search the entire index space across all partitions. Always much slower than local indexes, especially as the dataset grows.
Avoid inequality (>, <, >=, <=) and IN operators in
filtered vector queries - they force the database to scan a much larger
portion of the index, with performance degrading proportionally to
selectivity.
See Filtering for examples and details.
Can I use Vector Search with Alternator (the DynamoDB API)?¶
Yes. Starting with ScyllaDB 2026.2.0, you can use vector search through the DynamoDB-compatible Alternator API, storing embeddings as lists of numbers. The core workflow — storing vectors, building a vector index, and running ANN queries — is supported.
Some CQL capabilities are not available through Alternator in the 2026.2.x series, including configurable similarity functions, similarity scores, metadata filtering, HNSW index tuning, and quantization.
See Vector Search with Alternator for details and Python examples.
What is quantization and when should I use it?¶
Quantization reduces the precision of stored vectors to save memory. Instead of storing each dimension as a 4-byte float (f32), you can use:
f16 (2 bytes) — negligible recall loss for most workloads.
bf16 (2 bytes) — brain float, statistically equivalent to f16 for most models.
i8 (1 byte) — ~4x compression on vector data.
b1 (0.125 bytes) — ~32x compression on vector data; best with rescoring.
Note that quantization compresses only the vector data, not the HNSW graph
structure, so actual total memory savings are always less than the per-dimension
compression ratio. For example, i8 is 4x smaller per dimension than
f32, but total index memory typically drops only ~3x.
Use quantization when your dataset is large enough that f32 indexes would exceed available memory. Combine with oversampling and rescoring to recover accuracy.
See Quantization and Rescoring for configuration guidance.
Are partition deletes and range deletes supported?¶
Partition deletes (DELETE FROM t WHERE pk = ?) and range deletes
(DELETE FROM t WHERE pk = ? AND ck > ?) on tables with clustering keys are
not propagated to the vector index. ScyllaDB filters out deleted rows at
query time, so they will not appear in ANN results. However, the stale entries
in the vector index still consume candidate slots, which can cause ANN queries
to return fewer results than the requested LIMIT. They also continue to
consume memory on the indexing nodes.
To avoid this, always delete rows using a fully specified primary key (all partition key and clustering key columns). See CQL Features Not Supported for details.
How do I estimate the memory needed for my vector index?¶
Use this simplified formula:
Where N = number of vectors, D = dimensions, B = bytes per dimension
(4 for f32, 2 for f16, 1 for i8), and m = maximum_node_connections
(default: 16).
For worked examples, see the Sizing Guide.
Do I need an indexing node in every Availability Zone?¶
No. The recommended production topology places one indexing node in each Availability Zone (AZ) — so that every ScyllaDB node has a co-located vector index — but ScyllaDB Cloud also supports deploying fewer indexing nodes than storage nodes. For example, a three-node ScyllaDB cluster with a replication factor of 3 (RF=3) across three AZs can run with just two indexing nodes.
Two nodes keep the vector index redundant (vector search survives the loss of one node) while lowering the cost of the Vector and Text Search tier. The trade-offs are some cross-zone query traffic (negligible at low QPS), slightly higher latency for the one AZ that has no local indexing node, and high availability that becomes regional rather than zonal.
See Node Placement and Availability Zones for a full comparison of the two topologies and guidance on when to choose each.
Does ScyllaDB generate embeddings?¶
No. ScyllaDB stores and indexes vectors but does not generate them. Your application must use an external embedding model (OpenAI, Cohere, sentence-transformers, etc.) to produce vectors, then insert them into ScyllaDB.
See How Embeddings Work in the Concepts page.
Do I need to use the same embedding model for indexing and querying?¶
Yes. Vectors from different models exist in incompatible vector spaces and cannot be meaningfully compared. If you change your embedding model, you must re-embed all existing data. You can update the embeddings for all rows in the table and they will be refreshed in the index, but for performance reasons it is better to drop the index, update the data, and rebuild the index from scratch.
Why do vector tables require tablets-enabled keyspaces?¶
The HNSW vector index relies on ScyllaDB’s tablets data distribution mechanism for efficient data routing and sharding. Tablets provide fine-grained load balancing and dynamic rebalancing that the vector index depends on.
All ScyllaDB versions currently used by ScyllaDB Cloud enable tablets by default. If you still use a vnode-based cluster, you can create a separate tablets-enabled keyspace specifically for storing embeddings to overcome this limitation.
What does “recall” mean for vector search?¶
Recall is the fraction of true nearest neighbors found by the approximate search. A recall of 0.95 means 95% of the results match what an exact brute-force search would return. The remaining 5% are still genuinely similar vectors — they are just not the very closest ones.
You can increase recall by raising search_beam_width (ef_search),
at the cost of higher query latency. See
HNSW Parameters Explained.
Can I run exact (brute-force) vector search in ScyllaDB?¶
ScyllaDB’s vector search uses ANN (Approximate Nearest Neighbor) via the
HNSW algorithm. There is no dedicated exact KNN mode. However, for small
datasets, you can set a very high search_beam_width to achieve
near-perfect recall.
For most use cases, ANN with default parameters provides recall above 0.95, which is functionally equivalent to exact search.
Is TTL supported on vector-indexed columns?¶
Per-row TTL is supported; cell-level TTL is not.
Starting with ScyllaDB 2026.2.0, vector-indexed tables support automatic
row expiration through ScyllaDB’s per-row TTL feature. You designate one
column as the expiration-time column with the TTL keyword. When a row’s
expiration time passes, ScyllaDB deletes the row and the Vector Store removes
it from the index, so it no longer appears in ANN OF query results.
CREATE TABLE myapp.sessions (
id uuid PRIMARY KEY,
embedding vector<float, 5>,
expire_at bigint TTL -- seconds since the UNIX epoch
);
CREATE CUSTOM INDEX ann_idx ON myapp.sessions(embedding) USING 'vector_index';
-- The row is removed from the table and the vector index once expire_at passes.
INSERT INTO myapp.sessions (id, embedding, expire_at)
VALUES (uuid(), [0.1, 0.15, 0.3, 0.12, 0.05], 1784311784);
Classic cell-level TTL is not supported: neither USING TTL on an
individual write nor the default_time_to_live table property is propagated
to the vector index. ScyllaDB accepts these statements and the data does expire
from the base table, but cell expiration generates no CDC event, so the vector
is never removed from the HNSW graph. The expired data does not reappear in
results, but the stale entries consume memory and can make ANN queries return
fewer results than the requested LIMIT.
See Row Expiration with Per-Row TTL for supported column types, expiration timing, how to manage the TTL column on an existing table, and details on the cell-level TTL limitation.
How do I alter a vector index (change similarity function or HNSW parameters)?¶
You cannot alter a vector index after creation. However, you can recreate the index with a new configuration.
Starting with ScyllaDB 2026.2, you can create a second vector index on the same column. The old index continues serving queries while the new one is being built, and queries are automatically routed to the new index once it is ready:
Ensure enough memory for both indexes on the indexing nodes.
Create the new index on the same column with a different name.
Wait for the new index to finish building (queries keep using the old index automatically).
Drop the old index.
Resize the instance down if memory allows.
On versions prior to 2026.2, a single vector column can only have one index at a time. To change the index configuration you must migrate to a new column:
Add a duplicate vector column to the table.
Dual-write embeddings to both the original and new columns.
Backfill the new column for all existing rows.
Ensure enough memory for both indexes on the indexing nodes.
Create the new index (with updated options) on the duplicate column.
Switch your application queries to the new column.
Drop the old index and column.
Resize the instance down if memory allows.
See Altering a Vector Index in the Working with Vector and Text Search page for a step-by-step walkthrough with examples.
Can I get similarity distance scores in query results?¶
Yes. You can retrieve similarity scores by calling one of the built-in
similarity functions in your SELECT query:
similarity_cosine(<vector>, <vector>)similarity_euclidean(<vector>, <vector>)similarity_dot_product(<vector>, <vector>)
Each argument can be either a vector column name or a vector literal. Both arguments must have the same dimension.
For example:
SELECT comment, similarity_cosine(comment_vector, [0.1, 0.15, 0.3, 0.12, 0.05])
FROM myapp.comments_vs;
Each function returns a float value in the range [0, 1], where values
closer to 1 indicate greater similarity. The similarity_euclidean and
similarity_dot_product functions do not perform vector normalization
prior to computing similarity.
Note
similarity_dot_product assumes that all input vectors are
L2-normalized. Supplying non-normalized vectors will produce values that
are not meaningful for similarity comparison. If your vectors are not
normalized, use similarity_cosine instead.
Which ScyllaDB version do I need for full text search?¶
ScyllaDB 2026.3.0 or later. Full text search runs on the same indexing nodes as vector search, so a cluster with Vector and Text Search enabled and running 2026.3.0 or later can use both. Vector search alone is available from 2025.4.3. See Feature Compatibility Matrix.
When should I use full text search instead of vector search?¶
Use full text search when the exact words matter — searching for a product name, an error code, or a quoted phrase. Use vector search when the meaning matters and the wording may differ, which is what makes semantic search and RAG work.
They are complementary, and many applications benefit from running both and merging the results. See Combining Full Text and Vector Search.
Can I combine BM25 and ANN in one query?¶
No. ScyllaDB rejects a query containing both with BM25 and ANN cannot be
combined in the same query.
A single table can carry both a full-text index and a vector index, so run the two queries separately and fuse the result sets in your application — for example with Reciprocal Rank Fusion. See Combining Full Text and Vector Search.
Can I filter a full text search query on another column?¶
No. A full text search query cannot carry any WHERE restriction beyond the
BM25() clause itself — not on the partition key, not on another column,
and ALLOW FILTERING does not change this. The server responds with
Full-text search queries do not support additional WHERE restrictions.
Retrieve the top matches and apply any further filtering in your application. Note that this differs from vector search, which does support filtering.
Why doesn’t a search for “run” match “running”?¶
The default standard analyzer does not apply stemming, so a term matches
only in the form in which it appears in the text. Create the index with a
language analyzer to make different inflections match each other:
CREATE CUSTOM INDEX articles_body_fts ON blog.articles(body)
USING 'fulltext_index'
WITH OPTIONS = {'analyzer': 'english'};
With english, a search for run matches running and runners. Pick
the analyzer for the language of your text — see Choosing an Analyzer.
The analyzer is fixed for the life of the index, so on an existing
standard index you either combine the forms with OR
('run OR running OR runs') or drop the index and recreate it with the
language analyzer.
Fuzzy (term~1) and prefix (term*) matching remain unavailable — they
parse without error but match nothing.
Why is my boolean full text search query not narrowing the results?¶
Most likely the operator was written in lower case. Unlike CQL, the text query
language passed to BM25() recognizes AND, OR, and NOT only in
upper case. A lowercase and, or, or not is treated as an
ordinary search term, and since all three are English stop words it is then
dropped — leaving the remaining terms joined by the implicit OR.
Nothing reports an error, so the query silently widens instead of narrowing:
-- Narrows to rows containing both terms.
SELECT id FROM blog.articles
WHERE BM25(body, 'database AND distributed') > 0
ORDER BY BM25(body, 'database AND distributed')
LIMIT 10;
-- Does NOT narrow: same result as 'database OR distributed'.
SELECT id FROM blog.articles
WHERE BM25(body, 'database and distributed') > 0
ORDER BY BM25(body, 'database and distributed')
LIMIT 10;
See Boolean Operators.
Can I change the analyzer of an existing full-text index?¶
No. There is no ALTER INDEX statement, so the analyzer and
positions options are fixed when the index is created. To change either
one, drop the index and create it again:
DROP INDEX IF EXISTS blog.articles_body_fts;
CREATE CUSTOM INDEX articles_body_fts ON blog.articles(body)
USING 'fulltext_index'
WITH OPTIONS = {'analyzer': 'english'};
The new index is rebuilt from the base table, and full text search queries on that column fail until the rebuild finishes. See Index Options.
Can I get BM25 relevance scores in query results?¶
No. BM25() cannot appear in the SELECT list; the server responds with
BM25() is not supported in the SELECT clause. Results are returned in
descending relevance order, so you get the ranking rather than the numbers.
Why is my full text search limited to 1000 rows?¶
LIMIT is mandatory on a full text search query and must not exceed 1000,
and results are not paged. Narrow the query with additional terms rather than
paging through matches. See Result Size and Paging.
How long until new text is searchable?¶
A few seconds. Writes reach the full-text index asynchronously through CDC, the same mechanism used for vector indexes. Deletes remove the row from the index, and updating an indexed column replaces the old text. See Write-to-Query Latency.
What’s Next¶
Working with Vector and Text Search — CQL syntax for vector tables, indexes, and ANN queries.
Working with Full Text Search — CQL syntax for full-text indexes and
BM25()queries.Vector and Text Search Concepts — deep dive into HNSW, similarity functions, and architecture.
Troubleshooting — common issues and solutions.