--- title: "The vector index" slug: "dev-vector-search-concepts-index" description: "Learn about vector-indexed tables, indexing rules, and search strategies for efficient querying in the VAST Query Engine. Optimize your data management today!" updated: 2026-10-30T18:18:51Z published: 2026-10-30T18:18:51Z canonical: "docs.vastdata.com/dev-vector-search-concepts-index" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.vastdata.com/llms.txt > Use this file to discover all available pages before exploring further. # The vector index *Applies to VAST Cluster 5.5.* This page covers the ideas the rest of the Vector Search docs rely on: what you define when you create a vector-indexed table, what happens to the rows afterwards, and the rules a search has to follow to use the index. For how the index works inside the cluster, see [architecture](/develop/docs/dev-vector-search-concepts-architecture). ## Objects | Object | What it is | | --- | --- | | Vector column | A column of SQL type `VECTOR(<element type>, <dimension>)`, for example `VECTOR(FLOAT, 768)`. These docs use `FLOAT` elements; `FLOAT16` (alias `HALF`) also works. The length is fixed: inserting a vector of another length fails. | | Vector index | Clustering of the table's data on one vector column. You create it with the table (`VECTOR CLUSTER BY`) and can't add it later. You can't drop it or re-create it. A table has at most one. | | Distance metric | How "near" is computed, both for clustering and for search: `l2sq` (Euclidean), `cosine` or `ip` (inner product). You can't change it after the table is created. | | Cluster quantization | The encoding the index uses when it builds and stores its clusters: `none` or `scalar_8bit`. Set when the table is created. | | Search quantization | The encoding used for distances while a search walks the index: `none` or `scalar_8bit`. Set when the table is created. | | Recent rows | Rows inserted since the last indexing pass, which aren't in the index yet. Every search reads them directly, by brute force, so they're found straight away. | An index is designated when the table is created, can't be designated afterwards and can't be removed, and only one vector column per table can be indexed (see [Vector database index](/docs-5-5/docs/vector-database-index)). Every decision you make at creation, and what each one rules out, is in [design a vector table](/develop/docs/dev-vector-search-guides-table-design). Both quantization settings default to `scalar_8bit`, and not every pair is allowed. See [quantization](/develop/docs/dev-vector-search-guides-quantization). Avoid naming a column `vector`. It's a reserved word in the VAST Query Engine, and unquoted it's a syntax error. In the Python SDK, a vector column is a fixed-size Arrow list of `float32` whose items aren't nullable: `pa.list_(pa.field("item", pa.float32(), nullable=False), dim)`. ## Terms | Term | Meaning | | --- | --- | | Approximate nearest-neighbour (ANN) search | A search that uses the vector index. It returns close matches quickly, but it can miss some of the exact nearest neighbours. | | Probe | Opening a cluster of the index during a search. How many clusters a search opens at each level is its probe budget: more probes usually means better recall and more latency. The [search session settings](/develop/docs/dev-vector-search-reference-configuration) set the budget. | | Recall@K | The fraction of the exact top *K* rows that a search with the index also returns in its top *K*. See [measure recall and latency](/develop/docs/dev-vector-search-guides-developer-observability). | | Query Engine VIP pool | A virtual IP pool with the Query Engine role. Your client reaches the VAST Query Engine through its addresses ([VAST Query Engine](/docs-5-5/docs/vast-query-engine#creating-virtual-ip-pools-for-the-vast-query-engine)). See [setup](/develop/docs/dev-vector-search-operations-setup). | | Clustering grade | How far the index has caught up with the table's rows, from C up to A+. A grade of C doesn't mean the index isn't used. See [performance and sizing](/develop/docs/dev-vector-search-operations-performance#check-the-index-first). | ## Lifecycle ![Your writes, with SQL INSERT, ADBC bulk ingest, or the Python SDK's insert() or import_files(), are searchable once they commit. New rows land as recent rows, which aren't in the index yet and are read directly by every search. In the background, initial indexing places recent rows into the index, a hierarchy of clusters, and reclustering keeps refining that hierarchy. A search reads both: it walks the index's clusters and reads the recent rows directly, so new rows are always found, but a large backlog of recent rows makes every search do more work and run slower. An UPDATE of the vector column is rejected: to change a vector, delete the row and insert it again, and the new row joins the recent rows. With the session setting vector_search_skip_recent_non_indexed set to 1, a search reads only the index, so recent rows can be missing from its results.](https://cdn.us.document360.io/89b91113-5dc6-49db-86ec-57b16dc8ce56/Images/Documentation/vs-index-lifecycle.svg?sv=2026-02-06&spr=https&st=2026-11-08T08%3A55%3A23Z&se=2026-11-08T09%3A55%3A23Z&sr=c&sp=r&sig=o%2B4ikpnJDeDU3tlQ%2FEeyKoyyZbr5%2FsjG2DscIl3Pa6c%3D) *New rows are searchable at once as recent rows; background indexing moves them into the index.* 1. **Create** an empty table with `VECTOR CLUSTER BY`. See [create an index](/develop/docs/dev-vector-search-guides-create-an-index). 2. **Ingest** with SQL `INSERT`, the SDK's `insert()` or `import_files()`, or ADBC bulk ingest. See [ingest](/develop/docs/dev-vector-search-guides-ingest). 3. **Initial indexing.** In the background, the cluster takes the recent rows and places them into clusters of the index. 4. **Reclustering.** Also in the background, the cluster refines the hierarchy with k-means clustering. 5. **Query** at any time after the insert commits. Until indexing has caught up, a search reads more rows directly, so it's slower. Judge speed and recall once indexing has caught up with your load: the clustering grade shows how far it has got. With the session setting `vector_search_skip_recent_non_indexed` set to `"1"`, a search reads only the index, so recent rows can be missing from its results ([search session settings](/develop/docs/dev-vector-search-reference-configuration)). 6. **Change rows.** `UPDATE` of non-vector columns and `DELETE` work. You can't update a vector value: the cluster rejects it. To change a vector, delete the row and insert it again, so the new vector is placed in the right cluster. ## What distance values mean An embedding model turns a piece of data, such as a text chunk, an image or a video frame, into a vector: a fixed-length array of numbers that captures its meaning, not its exact content. Vectors that are near each other represent data with similar meaning. The vectors embedding models produce for semantic search are **dense**: most of their elements hold a value. **Sparse** vectors, where nearly every element is zero (used for keyword-style, lexical search), aren't supported in VAST Cluster 5.5: there's no sparse vector type, and a `VECTOR` column holds a fixed-length list of numbers ([supported data types](/docs-5-5/docs/supported-data-types)). How "near" is measured depends on the table's metric, and each metric has a distance function you use in SQL. All three distance functions follow one rule: **smaller is more similar**. That's why every search sorts by distance ascending. | Metric | Distance function | What it measures | Range | 0 means | | --- | --- | --- | --- | --- | | `l2sq` | `array_distance` | Euclidean distance: the straight-line distance between the two vectors. It depends on both their direction and their length. | 0 to +∞ | The vectors are identical. | | `cosine` | `array_cosine_distance` | 1 − cosine similarity. Cosine similarity compares only the angle between the vectors, not their length, and runs from −1 (opposite) through 0 (unrelated) to 1 (same direction). | 0 to 2 | Same direction. 1 means perpendicular (unrelated) and 2 means opposite. | | `ip` | `array_negative_inner_product` | The inner (dot) product, with its sign flipped. The inner product is the vectors' lengths multiplied together and by the cosine of the angle between them, so it rewards both direction and length. | −∞ to +∞ | Nothing special: values are negative for similar vectors and positive for dissimilar ones. Only the order matters. | For example, with the query vector `[1, 1]`, the stored vector `[3, 3]` points the same way but is three times as long. Its distances are 2.83 (Euclidean), 0 (cosine) and −6 (negative inner product): cosine ignores the difference in length, Euclidean distance counts it against the match, and inner product counts it in its favour. The stored vector `[1, 0]` is at Euclidean distance 1 and cosine distance 0.29 (an angle of 45°), and its negative inner product is −1. What this means in practice: - **Use the metric your embedding model was trained for.** Its documentation says which. Many text-embedding models are meant for cosine. If a model produces vectors of length 1 (normalised), cosine, Euclidean and inner product rank results the same way. - **Compare distances only within one search.** A distance has no fixed meaning across metrics or models: 0.3 can be close for one model and far for another. If you need a cut-off, such as "only return chunks closer than X", find it by testing with your own data and model. - **`array_distance` returns the Euclidean distance itself, not its square,** even though the metric is called `l2sq`. Ranking is the same either way. - **The similarity forms sort the other way.** `array_cosine_similarity` and `array_inner_product` grow as vectors get more similar. Sorting them descending doesn't use the index, and sorting them ascending returns the least similar rows first. Search with the distance functions above ([query design](/develop/docs/dev-vector-search-guides-query-design#metric-and-function)). ## Rules for a search that uses the index A search on the index is an approximate nearest-neighbour search. The Query Engine walks the index from the top, level by level, and opens only the clusters nearest the query vector; [architecture](/develop/docs/dev-vector-search-concepts-architecture#what-happens-when-you-search) explains the walk. For the walk to happen, the query must have this shape: ``` SELECT , , (vec::FLOAT[d], ARRAY[...]::FLOAT[d]) AS dist FROM "bucket/schema".table WHERE ORDER BY dist ASC LIMIT k; ``` - **Use the distance function that matches the index's metric.** | Metric | Distance function | | --- | --- | | `l2sq` | `array_distance` | | `cosine` | `array_cosine_distance` | | `ip` | `array_negative_inner_product` | A query with a different distance function still runs, but it doesn't use the index: it computes the distance for every row. - **Smaller is nearer.** `ORDER BY dist ASC`. For inner product, use the negative function, so ascending order still puts the best match first: `array_inner_product` sorted ascending returns the *least* similar rows first. The SDK's `vector_search()` has the same problem on `ip` tables; see [Python SDK](/develop/docs/dev-vector-search-integrations-python-sdk). - **One sort key and a `LIMIT`, no `OFFSET`.** Sort by the distance only, ascending, with a `LIMIT`. A search with `OFFSET` runs, but it doesn't use the index. - **Match the dimension.** Cast both sides to the column's width, `FLOAT[d]` (or `FLOAT16[d]`). - **Filters in `WHERE` work** alongside the ranking, and row and column security applies to the user running the search ([Vector search](/docs-5-5/docs/vector-search#filtering-vector-searches)). - **Order by a distance, not a similarity.** A similarity sorted descending, as in some slides and webinars, runs as a full scan and doesn't use the index; use the distance ascending. (There's no `cosine_similarity` function; `array_cosine_similarity` exists, but doesn't use the index.) See [query design](/develop/docs/dev-vector-search-guides-query-design#queries-that-dont-use-the-index). `EXPLAIN` shows whether a search uses the index: its plan contains a `VAST_VEC_INDEX_SCAN` step. [Query design](/develop/docs/dev-vector-search-guides-query-design) has the full rules, with captured examples of each. ## What "indexed" doesn't mean - **It isn't HNSW, IVF or another vendor's index.** It's hierarchical clustering, with recent rows read directly until they're indexed. See [architecture](/develop/docs/dev-vector-search-concepts-architecture). - **It isn't a separate namespace.** You search the same table you insert into. - **It isn't self-training.** The clustering is a data structure, not a model. ## See also - [Architecture](/develop/docs/dev-vector-search-concepts-architecture): how the index is laid out and searched. - [Quickstart](/develop/docs/dev-vector-search-quickstart): an indexed table end to end. - [Limits](/develop/docs/dev-vector-search-reference-limits) and the VAST DataBase [limits on combining table structures](/develop/docs/dev-database-reference-limits#combining-table-structures).