Vector Inputs
All eight cuVS UDTFs take relation arguments as parenthesized SELECT
subqueries. Each subquery remains a planner child. For gpu_validate_call,
register a table or view with the same schema. Metadata validation does not
evaluate rows.
Relation identity
Every dataset, queries, x, y, or input binding names a logical ID
column:
- The ID must be
Int32,Int64,Utf8,LargeUtf8, orUtf8View, and no ID may be null. - IDs may repeat. Result ordinals disambiguate physical rows with equal IDs.
- A subquery's top-level
ORDER BYfixes the order its rows are numbered in. Sort keys must be output columns of the subquery, by name or 1-based position. Other keys are rejected withinput_ordering_key_not_projectedunlessLIMIT,OFFSET, orFETCHbounds the rows. Without a top-levelORDER BY, row order is unspecified, and rows that tie on every key have no stable order. - The ID comes from a relation field. Name the field in each JSON binding with
"id". cuVS does not assign a logical ID from row position.
Dense-vector binding shapes
Each binding chooses one vector shape. Feature order defines dimension order.
A SQL call infers the binding from the subquery's field types. When the only
field besides id is a FixedSizeList, List, or LargeList, that field is
the list column, whatever its name. Otherwise every field besides id is a
wide feature column. A list field next to other feature fields is rejected
with list_vector_with_additional_features.
Wide columns
{"id":"paper_id","vector":{"columns":["d0","d1","d2"]}}
columnscontains at least one unique, non-empty column name.- Each selected feature column holds no null values. All columns in the binding share one supported element type.
- The listed order defines the vector dimensions.
One list column
{"id":"paper_id","vector":{"column":"embedding"}}
embeddingisFixedSizeList<T, D>,List<T>, orLargeList<T>with a supported element typeT, and no row of it is null.- List elements hold no null values.
FixedSizeListhas a positive dimensionD. - Variable-width
ListandLargeListrows must have one uniform, positive dimension after evaluation.
Relation size
cuDF indexes the values of a list column with 32-bit offsets. One relation
argument can therefore hold at most 2,147,483,647 list values in its vector
column, which is 1,048,575 rows of a 2048-dimension FixedSizeList. The same
limit applies to each intermediate result inside the subquery. Separate scalar
feature columns hold up to 2,147,483,647 rows each.
A subquery may scan and filter a larger Parquet file. The source planner reads
it in parts that each stay under the limit, sized from the footer's value
counts or, without a footer, from fixed list widths, and only the rows the subquery
returns count toward the relation. A relation above the limit fails the query
with size_overflow. The message names the column, its value count and the row
count that fits at its width. Filter the subquery to fewer rows, or split the
dataset into row ranges, run one call per range and combine the results with
UNION ALL. For brute-force kNN over a split dataset, keep the k smallest
distances per query across the parts.
Null values
Schema nullability does not matter. A nullable field type is accepted for the
ID, for every feature column, and for a list column and its elements. Results
of aggregates, Parquet columns, and lists built in SQL therefore need no
rewrite. The contract applies to values. A null ID, a null feature value, a
null list row, or a null list element fails the query with an invalid-input
error (rapids_invalid_input) that names the function, the relation role, and
the column. gpu_validate_call reads no values and cannot find nulls.
Add COALESCE(column, CAST(0 AS REAL)) only when the data contains nulls and a
fallback value is correct, or drop the offending rows with
WHERE column IS NOT NULL.
A list vector built in SQL with ARRAY_AGG, MAKE_ARRAY, or
COALESCE(..., ARRAY_REPEAT(...)) is computed by DataFusion on the CPU,
because native lowering does not build lists. Its result is uploaded as the
relation and accepted when it contains no null rows or elements.
Element types
Floating vector values must be finite. NaN and infinity are rejected.
Integer elements have no finiteness requirement. All vector bindings in one
call share an element type and dimension. cuVS does not cast vector elements
implicitly. Use CAST in a relation subquery to select a supported type.
Float16 is unsupported because cuDF has no Float16 representation.
Vector element and metric support by UDTF
Each cell lists valid metric values for that input element. Yes means the element is supported without a metric option; No means the element is unsupported.
Brute-force kNN and the three ANN UDTFs return Float32 distance values.
Pairwise distance follows the input float width (Float32 or Float64).
KMeans cluster_id remains Int32.
Float32 expanded squared L2 evaluates ||x||² + ||y||² - 2 x·y.
Roundoff and cancellation near zero can produce a small positive distance
even for identical vectors; negative roundoff is clamped to zero. Positive
distances are retained. Equal rounded norms do not establish vector equality.
Near-tied distances can change neighbor selection at the k boundary, and
the returned IDs may differ between distance implementations. The API specifies
no fixed numerical tolerance or bit-exact zero for arbitrary Float32 inputs.
What validation can prove
gpu_validate_call checks the JSON envelope, relation existence,
field names, static types, binding shapes, duplicate wide-column names,
matching element types, valid element/metric pairs, and scalar option ranges.
It does not evaluate subqueries, scan values, or launch cuVS. Known relation
cardinalities and fixed-size dimensions may also be checked during SQL
planning. The following constraints are checked against evaluated rows when
those facts are not known statically:
Scalar checks do not require evaluated rows: IVF search requires
n_probes <= n_lists; CAGRA requires k <= itopk_size and
intermediate_graph_degree > graph_degree. CAGRA also rejects cosine with
nn_descent, and single_cta requires itopk_size <= 1024. A nonzero IVF-PQ
pq_dim * pq_bits must be divisible by 8.
cuVS calls execute inside the admitted query memory domain. Allocation beyond the configured cap fails at the allocator. See Integration for embedded and Flight SQL setup.