Vector Functions

Vector functions provide comprehensive operations for vector embeddings, similarity search, and machine learning workflows. These functions are available in both SQL and Cypher queries.

Every vector function has two equivalent names: the namespaced vector.<name>() form (e.g. vector.dimension()) and a camelCase alias kept for backward compatibility (e.g. vectorDimension()). They resolve to the same function and are case-insensitive.

Prefer the namespaced vector.<name>() form in new queries and examples: it groups the suite consistently with the other extended namespaces (geo., math., …​) and reads more clearly. The namespaced form can be called directly, without back-ticks (e.g. SELECT vector.cosineSimilarity(a, b)). All examples in this section use it.

Aggregation Functions

There are two distinct categories of "statistics" functions, which is easy to confuse:

  • Row aggregates that return a vector - vector.sum(), vector.avg(), vector.min(), vector.max() fold a column of vectors element-wise across rows. For example vector.avg(embedding) returns the centroid (the element-wise arithmetic mean) of all the embeddings in the result set.

  • Per-vector element statistics that return a scalar - vector.variance() and vector.stddev() operate on a single vector and return the variance / standard deviation of that vector’s elements. They are intentionally not row aggregates (unlike the scalar SQL variance()/stddev()).

vector.sum()

Aggregate function: element-wise sum of vectors.

Syntax: vector.sum(<field>)

Returns: Vector - Sum of all vectors

SELECT vector.sum(embedding) FROM documents

vector.avg()

Aggregate function: element-wise average of vectors.

Syntax: vector.avg(<field>)

Returns: Vector - Average vector

SELECT vector.avg(embedding) FROM documents

vector.min()

Aggregate function: element-wise minimum of vectors.

Syntax: vector.min(<field>)

Returns: Vector - Minimum vector

SELECT vector.min(embedding) FROM documents

vector.max()

Aggregate function: element-wise maximum of vectors.

Syntax: vector.max(<field>)

Returns: Vector - Maximum vector

SELECT vector.max(embedding) FROM documents

Basic Operations

vector.dimension()

Returns the dimension of a vector (length of the underlying array).

Syntax: vector.dimension(<vector>)

Returns: Integer - Vector dimension. A NULL argument returns 0 (consistent with .size()/.length()).

SELECT vector.dimension([1.0, 2.0, 3.0])
-- Returns: 3

SELECT vector.dimension(null)
-- Returns: 0
RETURN vector.dimension([1.0, 2.0, 3.0]) AS dim

vector.add()

Returns element-wise sum of two vectors, or adds a scalar to every element (broadcasting). The scalar may be either argument since addition is commutative.

Syntax: vector.add(<vector1>, <vector2> | <scalar>)

Returns: Vector - Sum vector

SELECT vector.add([1.0, 2.0, 3.0], [2.0, 3.0, 4.0])
-- Returns: [3.0, 5.0, 7.0]

SELECT vector.add([1.0, 2.0, 3.0], 4.0)
-- Returns: [5.0, 6.0, 7.0]  (scalar broadcasting)

vector.subtract()

Returns element-wise difference of two vectors, or subtracts with a scalar (broadcasting). Order is preserved: vector - scalar subtracts the scalar from each element, while scalar - vector subtracts each element from the scalar.

Syntax: vector.subtract(<vector1> | <scalar>, <vector2> | <scalar>)

Returns: Vector - Difference vector

SELECT vector.subtract([3.0, 5.0, 7.0], [1.0, 2.0, 3.0])
-- Returns: [2.0, 3.0, 4.0]

SELECT vector.subtract([1.0, 2.0, 3.0], 1.0)
-- Returns: [0.0, 1.0, 2.0]  (vector - scalar)

SELECT vector.subtract(10.0, [1.0, 2.0, 3.0])
-- Returns: [9.0, 8.0, 7.0]  (scalar - vector)

vector.scale()

Scales vector element-wise by a scalar value.

Syntax: vector.scale(<vector>, <scalar>)

Returns: Vector - Scaled vector

SELECT vector.scale([1.0, 2.0, 3.0], 2.0)
-- Returns: [2.0, 4.0, 6.0]

vector.clip()

Clips (clamps) vector elements to a specified range [min, max]. Also available as vector.clamp() / vectorClamp().

Syntax: vector.clip(<vector>, <min>, <max>)

Returns: Vector - Clipped vector

SELECT vector.clip([1.0, 5.0, 10.0], 2.0, 8.0)
-- Returns: [2.0, 5.0, 8.0]

SELECT vector.clamp([1.0, 5.0, 10.0], 2.0, 8.0)
-- Returns: [2.0, 5.0, 8.0]  (clamp is an alias of clip)

vector.neighbors()

Returns k nearest neighbors from a vector index.

Syntax:

vector.neighbors(<index-spec>, <query-vector>, <k>)
vector.neighbors(<index-spec>, <query-vector>, <k>, <efSearch>)
vector.neighbors(<index-spec>, <query-vector>, <k>, { <option>: <value>, ... })

Parameters:

  • index-spec - Index specification as 'TypeName[propertyName]'

  • query-vector - Query vector or key to look up

  • k - Number of neighbors to return. Must be a non-negative integer: 0 returns no rows (like LIMIT 0), a negative or fractional value is rejected with an error. The same rule applies to the k of vector.sparseNeighbors(), vector.discover(), vector.recommend() and vector.rerank(). Since 26.11.1 (a negative k returned no rows before).

  • efSearch - (optional, positional) Search beam width. Controls the trade-off between recall and speed. Higher values improve recall but increase latency. When omitted, the index uses its default beam, sized from the graph.

Options map (optional, alternative to the positional efSearch argument). An option of type Integer accepts a whole number only (2 or 2.0): a fractional value such as 2.5 is rejected with an error instead of being truncated, since 26.11.1.

Key Type Description

efSearch

Integer

Same semantics as the positional form.

filter

List of RIDs or RID strings

Restricts the search to the provided set of records. Useful to combine a vector search with a logical filter: first select the candidate RIDs, then pass them as filter. An empty list (or a subquery that returns no rows) matches nothing, so the function returns no results. Omit the option, or pass null, to search without a restriction. Unknown keys are rejected.

where

Map or String

Restricts the search to the records that satisfy a predicate, tested on each candidate as the search meets it: a map of property to value, every entry of which must hold with the SQL = semantics ({ embed_space: :space }, nested paths such as meta.source allowed), or a SQL condition ('year >= :minYear AND lang = :lang', whose parameters are the query’s). Unlike a filter subquery it does not load every record in scope and list its RID on every call: only the candidates the search considers are loaded, once each. Combined with filter, a candidate must be in the list and satisfy the predicate. Also accepted by vector.sparseNeighbors. Since 26.11.1.

groupBy

String

Diversifies the answer by a property: k becomes the number of distinct values of that property to return rather than the number of rows, and at most groupSize rows are returned per value. Supports nested paths (meta.source). Records whose property is missing share the single null group.

groupSize

Integer

Rows to return per group when groupBy is set. Defaults to 1, so the answer is the k nearest records with k distinct values. Must be >= 1; ignored when groupBy is absent.

maxDistance

Number

Drops neighbors further than this distance, turning the query into a radius search bounded by k. The result may legitimately hold fewer than k rows. Defaults to no bound.

rerank

Integer

PRODUCT and BINARY indexes only. Candidates per requested neighbor that the search, which walks the graph on the in-memory PQ codes (or one-bit codes for BINARY, since 26.11.1), scores again on the stored vectors before returning the nearest k with their exact distances. A BINARY index re-ranks at least one candidate per neighbor. 0 returns the PQ scores as they are, without reading a stored vector: fastest, but the recall of PQ scores alone is low and the distances are approximate (and not comparable across buckets, each of which has its own codebook). Defaults to the rerankOversample of the index (10). Ignored with groupBy and by the other quantizations. Since 26.11.1.

Prefer where to a filter subquery when the restriction is a property of the records and keeps a sizeable share of them: the subquery loads every record in scope on each call, the predicate only the candidates the search reaches. A filter remains the better choice for a small, precomputed list of RIDs, which the index can scan directly. A predicate that keeps few or none of the records leaves the graph walk short of k, and the search then tests every indexed record once to return an exact answer: the same cost the filter subquery pays on every call. The query’s timeout is checked before each record the predicate tests, so such a search stops at its deadline. The same applies to the WHERE of a Cypher SEARCH clause, which is tested by the index the same way.
Index the properties a selective where filters on. When the equalities of the predicate (the map form, or the property = value conditions of a SQL condition without OR) cover an LSM_TREE or HASH index, the search lists the matching records through that index as soon as it sees that the predicate keeps few records, and scores them directly instead of walking the graph (since 26.11.1). On 100,000 vectors, 20 matching records then cost about 0.3 ms instead of about 120 ms. A predicate that keeps a large share of the records keeps the graph walk, at no extra cost. The switch is bounded by arcadedb.vectorIndex.prefilterMaxSelectivity, and setting it to 0 disables it.

Returns: List - Nearest neighbors with distances

Each row holds the record’s properties, its @rid and @type, and the distance. The rows of vector.sparseNeighbors(), vector.fuse(), vector.rerank(), vector.mmr(), vector.boost() and vector.discover() have the same shape, with their own score. The record itself is reachable under the record key (record.name, or SELECT record FROM (…​)), which a re-ranker downstream uses to score the row without loading it again, but SELECT *, expand() and the JSON of the row do not list it, since its properties are the row’s already. Before 26.11.1 every row also carried the whole record under record, so each property was serialized twice.

-- Default beam
SELECT vector.neighbors('Document[embedding]', [0.1, 0.2, 0.3], 5)

-- Explicit efSearch for higher recall (positional form, backward compatible)
SELECT vector.neighbors('Document[embedding]', [0.1, 0.2, 0.3], 5, 500)

-- Options map form (named, extensible)
SELECT vector.neighbors('Document[embedding]', [0.1, 0.2, 0.3], 5, { efSearch: 500 })

-- Combine a vector search with a logical filter on the same type
SELECT vector.neighbors(
         'Document[embedding]',
         [0.1, 0.2, 0.3],
         10,
         { filter: (SELECT @rid FROM Document WHERE tenantId = 'acme' AND category = 'finance') }
       )

-- Using a parameter binding for the RID list
SELECT vector.neighbors('Document[embedding]', :queryVector, 10, { efSearch: 300, filter: :allowedRids })

-- Restrict by a property without listing every RID in scope
SELECT vector.neighbors('Document[embedding]', :queryVector, 10, { where: { tenantId: :tenant } })

-- ... or by any SQL condition
SELECT vector.neighbors('Document[embedding]', :queryVector, 10, { where: 'year >= :minYear AND category <> :excluded' })

-- One result per source document: 10 distinct sources, nearest chunk of each
SELECT vector.neighbors('Chunk[embedding]', :queryVector, 10, { groupBy: 'sourceFile' })

-- 5 distinct sources, up to 3 chunks each, none further away than 0.35
SELECT vector.neighbors(
         'Chunk[embedding]',
         :queryVector,
         5,
         { groupBy: 'sourceFile', groupSize: 3, maxDistance: 0.35 }
       )

groupBy changes how rows are capped and nothing else about what the index can see: a grouped query is answered from the same corpus as the ungrouped one, including vectors written since the graph was last rebuilt.

A grouped query can return fewer than k groups, and two index statistics tell you which of the two reasons applies:

  • groupedSearchesShortOfLimit - the search ran out of candidate budget before reaching the k-th nearest group, which happens when the nearest groups are very dense. Raising efSearch is what helps here.

  • groupedSearchesGroupsUnavailable - there were no more groups to find. Usually this simply means the data holds fewer distinct values of the groupBy property than you asked for: a query with k of 10 over a corpus with 3 source files can only ever return 3 groups. That is expected and needs no action - raising efSearch cannot create a group that does not exist, and only makes the query slower. Look into it only if you expected more groups than you got, which can indicate a damaged index graph that REBUILD INDEX repairs.

The options map rejects unknown keys with a descriptive error to catch typos, for example passing { efsearch: 500 } (lowercase) will fail. Keys are case sensitive.

Cypher Usage:

The recommended way to use vector search from Cypher is via CALL, which uses the HNSW index for fast approximate nearest neighbor search:

// ArcadeDB-native syntax
CALL vector.neighbors('Document[embedding]', $queryVector, 10)
YIELD name, distance
RETURN name, distance
ORDER BY distance

// Neo4j-compatible syntax (returns node + score)
CALL db.index.vector.queryNodes('Document[embedding]', 10, $queryVector)
YIELD node, score
RETURN node.title AS title, score
ORDER BY score DESC
db.index.vector.queryNodes() returns score in [0, 1] (1.0 = identical, as Neo4j reports it), while vector.neighbors() returns distance (0.0 = identical). For COSINE the relationship is score = 1 - distance / 2; for DOT_PRODUCT score = -distance; for EUCLIDEAN score = 1 / (1 + distance).
A WHERE after the YIELD runs on the k rows the search already returned, so it can leave fewer than k rows, or none. To filter during the search, pass the where or filter option: to vector.neighbors() in its options map (where since 26.11.1), as in SQL above, or to db.index.vector.queryNodes() in an optional fourth argument (since 26.11.1), for example CALL db.index.vector.queryNodes('Document[embedding]', 10, $queryVector, { where: { tenantId: 'acme' } }). The fourth argument is an ArcadeDB extension to the Neo4j signature.

Type-Specific Search with Inheritance:

When a vector index exists on a parent type, you can search specific child types:

-- Search only in EMBEDDING_IMAGE records
SELECT vector.neighbors('EMBEDDING_IMAGE[vector]', :queryVector, 10)

-- Search across all types (parent + children)
SELECT vector.neighbors('EMBEDDING[vector]', :queryVector, 10)

Normalization and Norms

vector.normalize()

Normalizes vector to unit length (L2 norm = 1.0).

Syntax: vector.normalize(<vector>)

Returns: Vector - Normalized vector

SELECT vector.normalize([3.0, 4.0])
-- Returns: [0.6, 0.8]

vector.isnormalized()

Checks if vector is normalized (L2 norm ≈ 1.0). The optional tolerance defaults to 0.001, which is an appropriate loose bound for ArcadeDB’s float vectors (sqrt(float eps) ≈ 3.45e-4); pass a smaller value to tighten the check.

Syntax: vector.isnormalized(<vector>, [tolerance])

Returns: Boolean - true if normalized

SELECT vector.isnormalized([0.6, 0.8])
-- Returns: true

vector.magnitude()

Computes L2 norm (Euclidean length) of vector. Also available as vector.l2Norm() / vectorL2Norm(), symmetric with vector.l1Norm() and vector.lInfNorm().

Syntax: vector.magnitude(<vector>)

Returns: Double - L2 norm

SELECT vector.magnitude([3.0, 4.0])
-- Returns: 5.0

SELECT vector.l2Norm([3.0, 4.0])
-- Returns: 5.0  (l2Norm is an alias of magnitude)

vector.l1norm()

Computes L1 norm (Manhattan norm) of vector.

Syntax: vector.l1norm(<vector>)

Returns: Double - L1 norm

SELECT vector.l1norm([1.0, 2.0, 3.0])
-- Returns: 6.0

vector.linfnorm()

Computes L∞ norm (maximum absolute value) of vector.

Syntax: vector.linfnorm(<vector>)

Returns: Double - L∞ norm

SELECT vector.linfnorm([1.0, -5.0, 3.0])
-- Returns: 5.0

Quantization

vector.quantizeint8()

Quantizes vector to 8-bit integers using min-max scaling.

Syntax: vector.quantizeint8(<vector>)

Returns: ByteArray - Quantized vector

SELECT vector.quantizeint8([0.1, 0.5, 0.9])

vector.dequantizeint8()

Dequantizes 8-bit integers back to float vector (approximate recovery). Pass the result of vector.quantizeint8() directly (the min/max are read from it), or supply the bytes with explicit min/max.

Syntax: vector.dequantizeint8(<result>) or vector.dequantizeint8(<quantized>, <min>, <max>)

Returns: Vector - Dequantized vector

SELECT vector.dequantizeint8(vector.quantizeint8([1.0, 2.0, 3.0]))
-- Returns: ~[1.0, 2.0, 3.0]

vector.quantizebinary()

Quantizes vector to binary (1 bit per dimension) using median threshold. The median is used (rather than a fixed value like 0) so the bits split ~50/50, which maximizes the information retained per bit for arbitrarily-centered embeddings.

Syntax: vector.quantizebinary(<vector>)

Returns: ByteArray - Binary quantized vector

SELECT vector.quantizebinary([0.1, 0.5, 0.9])

vector.dequantizebinary()

Reconstructs an approximate float vector from a binary-quantized result. Binary quantization keeps only one bit per dimension (the sign relative to the median), so this is lossy: each bit maps to highValue (default 1.0) when set or lowValue (default -1.0) when clear. Accepts the result of vector.quantizebinary() directly.

Syntax: vector.dequantizebinary(<quantized> [, <lowValue>, <highValue>])

Returns: Vector - Reconstructed (sign) vector

SELECT vector.dequantizebinary(vector.quantizebinary([0.1, 0.5, 0.9]))
-- Returns: [-1.0, 1.0, 1.0]

Scoring and Fusion

vector.fuse()

Fuses the ranked rows of two or more sources into one ranking, server-side. See Hybrid Search with vector.fuse for the strategies and worked examples.

Syntax: vector.fuse(<source1>, <source2>, …​ [, { <option>: <value>, …​ }])

Parameters:

  • source - At least two. Each is a list of rows carrying a @rid: the output of vector.neighbors or vector.sparseNeighbors, a sub-SELECT such as (SELECT @rid, $score FROM Doc WHERE SEARCH_INDEX('Doc[content]', :q) = true LIMIT 100), or SEARCH_INDEX('Doc[content]', :q) passed directly.

Options map:

Key Type Description

fusion

String

RRF (default), DBSF or LINEAR.

k

Integer

RRF constant. Defaults to 60.

weights

List of numbers

One weight per source. Defaults to 1.0 for each.

groupBy

String

Keeps at most groupSize rows per value of this property.

groupSize

Integer

Rows per group when groupBy is set. Defaults to 1.

limit

Integer

Maximum number of rows returned. Defaults to no limit: every fused candidate is returned, and loaded.

Returns: List - One row per fused record, with its properties and the fused score, best first.

Every row of every source is fused, and without limit every fused candidate is then loaded, so the cost grows with the number of rows the sources produce. A full-text leg without a LIMIT produces one row per match, so the query gets slower as the full-text match count grows, whatever k the other legs use. Bound both, as shown in Bounding the cost of a full-text leg.

Since 26.11.1, SEARCH_INDEX(…​) passed directly as a source carries the score of each match, so fusion: 'DBSF' and 'LINEAR' accept a full-text leg written that way (before, they refused it for lack of a score).


vector.rerank()

Re-scores the candidates of a first, cheaper search on full-precision vectors and returns the best k: the "prefetch and rerank" pattern. The first stage can use a lossy index (BINARY, PRODUCT, sparse, full-text) with a high over-fetch, since the rerank corrects its ranking.

Syntax: vector.rerank(<source>, <query-vector>, <embedding-property>, <k>)

Parameters:

  • source - The candidate rows: the output of vector.neighbors, vector.fuse, or a sub-SELECT returning records.

  • query-vector - The full-precision query vector.

  • embedding-property - The property holding each candidate’s full-precision vector. A candidate without it, or whose record no longer exists, is skipped. A vector whose dimension differs from the query’s is an error.

  • k - Number of rows to return.

Returns: List - The k candidates with the highest cosine similarity to the query vector, as a score, best first.

SELECT expand(`vector.rerank`(
    `vector.neighbors`('Doc[binary_embedding]', :qBinary, 1000),
    :qFull,
    'embedding',
    100))

Since 26.11.1, a candidate row that already carries its record (the rows of vector.fuse, vector.neighbors and a plain SELECT do) is scored on that record without being reloaded, and only the best k candidates are kept while scanning. The cost still includes reading the embedding of every candidate, so bound the source (k of vector.neighbors, limit of vector.fuse) to the number of candidates worth re-scoring.


vector.hybridscore()

Computes weighted average of two scores.

Syntax: vector.hybridscore(<score1>, <score2>, <alpha>)

Returns: Double - Weighted average

SELECT vector.hybridscore(0.8, 0.6, 0.7)
-- Returns: 0.7 * 0.8 + 0.3 * 0.6 = 0.74

vector.multiscore()

Combines multiple scores using a fusion method.

Syntax: vector.multiscore(<scores>, <method>, [weights])

Methods:

  • 'MAX' - Maximum score (ColBERT style)

  • 'AVG' - Arithmetic average

  • 'MIN' - Minimum score

  • 'WEIGHTED' - Weighted average (requires weights)

Returns: Double - Combined score

SELECT vector.multiscore([0.9, 0.7, 0.8], 'MAX')
-- Returns: 0.9

vector.rrfscore()

Computes Reciprocal Rank Fusion (RRF) for combining multiple rankings.

Syntax: vector.rrfscore(<rank1>, <rank2>, …​, [{ k: <long> }]) or vector.rrfscore([<ranks>], [{ k: <long> }])

Ranks may be passed as variadic arguments or grouped in a single array/list (consistent with vector.multiscore). Every positional numeric argument is treated as a rank. The center constant k (default 60) is set only via the trailing options map { k: <long> } - a bare trailing number is always a rank, never k.

Parameters:

  • k - Center rank constant (default: 60), via { k: <long> }

Returns: Double - RRF score

SELECT vector.rrfscore(1, 2, 4)
-- Returns: 1/61 + 1/62 + 1/64

SELECT vector.rrfscore([1, 2, 4], { k: 100 })
-- Returns: 1/101 + 1/102 + 1/104

vector.normalizescores()

Normalizes scores to [0, 1] range using min-max normalization.

Syntax: vector.normalizescores(<scores>)

Returns: Vector - Normalized scores

SELECT vector.normalizescores([1.0, 2.0, 3.0])
-- Returns: [0.0, 0.5, 1.0]

vector.scoretransform()

Transforms scores using various functions.

Syntax: vector.scoretransform(<score>, <method>)

Methods:

  • 'LINEAR' - No transformation

  • 'SIGMOID' - Logistic function, maps to (0, 1)

  • 'TANH' - Hyperbolic tangent, maps to (-1, 1)

  • 'LOG' / 'LN' - Natural logarithm (requires a positive score); LN is the clearer synonym

  • 'EXP' - Exponential function

Returns: Double - Transformed score

SELECT vector.scoretransform(0.5, 'SIGMOID')

SELECT vector.scoretransform(0.5, 'TANH')
-- Returns: 0.4621172

SELECT vector.scoretransform(2.5, 'LN')
-- Returns: 0.9162907  (same as 'LOG')

Similarity and Distance

vector.dotproduct()

Computes dot product (inner product) between two vectors.

Syntax: vector.dotproduct(<vector1>, <vector2>)

Returns: Double - Dot product

SELECT vector.dotproduct([1.0, 2.0, 3.0], [4.0, 5.0, 6.0])
-- Returns: 32.0

vector.cosinesimilarity()

Computes cosine similarity between two vectors. Returns value between -1 and 1.

Syntax: vector.cosinesimilarity(<vector1>, <vector2>)

Returns: Double - Cosine similarity (-1 to 1)

SELECT vector.cosinesimilarity([1.0, 0.0], [1.0, 0.0])
-- Returns: 1.0 (identical direction)

SELECT vector.cosinesimilarity([1.0, 0.0], [0.0, 1.0])
-- Returns: 0.0 (orthogonal)

vector.l2distance()

Computes L2 distance (Euclidean distance) between two vectors.

Syntax: vector.l2distance(<vector1>, <vector2>)

Returns: Double - Euclidean distance

SELECT vector.l2distance([0.0, 0.0], [3.0, 4.0])
-- Returns: 5.0

vector.approxdistance()

Computes approximate distance between quantized vectors without full dequantization. When you pass the result objects of vector.quantizeint8()/vector.quantizebinary(), the mode is inferred and the third argument can be omitted; the explicit mode is still required for raw byte arrays.

Syntax: vector.approxdistance(<quantized1>, <quantized2> [, <mode>])

Modes:

  • 'INT8' - Faster than floats; preserves the top-k ordering of the true distances (the approximate scalar distances rank in the same order, even though their absolute values differ). Accepts a vector.quantizeint8() result or a raw int8 byte array.

  • 'BINARY' - Very fast Hamming distance, 8x fewer operations. Requires the vector.quantizebinary() result object (raw packed bits are not enough - the Hamming normalization needs the original length).

Returns: Double - Approximate distance

-- mode inferred from the quantization result objects
SELECT vector.approxdistance(
  vector.quantizeint8([1.0, 2.0, 3.0]),
  vector.quantizeint8([1.0, 3.0, 3.0])
)

Sparse Vectors

vector.densetosparse()

Converts dense vector to sparse representation.

Syntax: vector.densetosparse(<vector>, [threshold])

Parameters:

  • threshold - Values below this are considered zero (default: 0.0)

Returns: SparseVector - Sparse representation

SELECT vector.densetosparse([0.5, 0.0, 0.1], 0.2)
-- Only keeps elements >= 0.2

vector.sparsetodense()

Converts sparse vector back to dense representation.

Syntax: vector.sparsetodense(<sparsevector>)

Returns: Vector - Dense vector

SELECT vector.sparsetodense(vector.sparsecreate([0, 2], [0.5, 0.3]))

vector.sparsecreate()

Creates sparse vector from indices and values.

Syntax: vector.sparsecreate(<indices>, <values>, [dimension])

Returns: SparseVector - Sparse vector

SELECT vector.sparsecreate([0, 2, 5], [0.5, 0.3, 0.8], 7)

vector.sparsedot()

Computes dot product between two sparse vectors.

Syntax: vector.sparsedot(<sparse1>, <sparse2>)

Returns: Double - Dot product

SELECT vector.sparsedot(
  vector.densetosparse([1.0, 2.0, 3.0]),
  vector.densetosparse([1.0, 1.0, 1.0])
)

vector.sparsity()

Returns a sparsity measure of a vector. The threshold is optional and defaults to sqrt(eps) for float (~3.45e-4). An optional third argument selects the measure.

Syntax: vector.sparsity(<vector> [, <threshold> [, <mode>]])

Modes:

  • 'FRACTION' (default) - fraction of elements with |x| < threshold, in [0, 1]

  • 'L0' - the L0 pseudonorm: count of "significant" elements with |x| >= threshold (integer)

  • 'GMEAN' - geometric mean of the absolute values, exp(mean(ln|x|)); returns 0 if any element is 0

Returns: Double (FRACTION, GMEAN) or Integer (L0)

SELECT vector.sparsity([0.01, 0.1, 0.05, 0.02], 0.06)
-- Returns: 0.75 (3 of 4 elements are below 0.06)

SELECT vector.sparsity([0.0, 1.0, 2.0, 3.0])
-- Returns: 0.25 (uses the default threshold; one near-zero element)

SELECT vector.sparsity([0.0, 1.0, 2.0, 3.0], 0.5, 'L0')
-- Returns: 3 (three significant elements)

SELECT vector.sparsity([1.0, 2.0, 4.0], 0.0, 'GMEAN')
-- Returns: 2.0 (geometric mean)

Statistics

vector.variance()

Computes variance of vector elements.

Syntax: vector.variance(<vector>)

Returns: Double - Variance

SELECT vector.variance([1.0, 2.0, 3.0])

vector.stddev()

Computes standard deviation of vector elements.

Syntax: vector.stddev(<vector>)

Returns: Double - Standard deviation

SELECT vector.stddev([1.0, 2.0, 3.0])

vector.hasnan()

Checks if vector contains NaN values. A NULL element (e.g. produced by an invalid math op such as sqrt(-1.0) that the engine coerces to NULL inside a collection) is treated as NaN.

Syntax: vector.hasnan(<vector>)

Returns: Boolean - true if contains NaN

SELECT vector.hasnan([1.0, 2.0, 3.0])
-- Returns: false

SELECT vector.hasnan([1.0, sqrt(-1.0), 3.0])
-- Returns: true (the NULL element counts as NaN)

vector.hasinf()

Checks if vector contains infinity values. A NULL element is treated as NaN, which is not infinite, so it does not trigger a true result.

Syntax: vector.hasinf(<vector>)

Returns: Boolean - true if contains infinity

SELECT vector.hasinf([1.0, 10e400, 2.0])
-- Returns: true

vector.hasnull()

Checks if a vector contains any NULL element. Unlike vector.hasnan(), this distinguishes a genuine NULL (a missing element) from a NaN float value. Primitive float[]/double[]/int[]/long[] inputs can never hold a NULL and therefore always return false.

Syntax: vector.hasnull(<vector>)

Returns: Boolean - true if contains a NULL element

SELECT vector.hasnull([1.0, 2.0, 3.0])
-- Returns: false

SELECT vector.hasnull([1.0, sqrt(-1.0), 3.0])
-- Returns: true

Utility Functions

vector.tostring()

Converts vector to string representation. Equivalent to the asString() method on a vector value (e.g. embedding.asString('PYTHON')); both share the same formatter.

Syntax: vector.tostring(<vector>, [format])

Formats:

  • 'COMPACT' - Single line [1.0, 2.0, 3.0] (default)

  • 'PRETTY' - Multi-line with formatting

  • 'PYTHON' - Python list format

  • 'MATLAB' - space-separated row vector [1.0 2.0 3.0]

  • 'MATLAB_COLUMN' - semicolon-separated column vector [1.0; 2.0; 3.0]

  • 'JULIA' - Julia vector literal [1.0, 2.0, 3.0]

  • 'NUMPY' - bare comma-separated 1.0, 2.0, 3.0 (no brackets), for numpy.fromstring(…​, sep=",")

Returns: String - Formatted vector

SELECT vector.tostring([0.5, 0.25, 0.75], 'PYTHON')

SELECT vector.tostring([0.5, 0.25, 0.75], 'NUMPY')
-- Returns: 0.5, 0.25, 0.75