[ 
https://issues.apache.org/jira/browse/CALCITE-7857?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18128550#comment-18128550
 ] 

Julian Hyde edited comment on CALCITE-7857 at 10/19/26 12:28 AM:
-----------------------------------------------------------------

Why a whole new data type? Why not {{ARRAY}} with a constraint?

{code:sql}
CREATE TABLE my_table (
  id INT,
  embedding ARRAY<REAL> CHECK (CARDINALITY(embedding) = 1536)
);
{code}

I believe that Calcite should support vectors, and this seems a well-considered 
proposal. I suspect that there are many others who would like vector support in 
Calcite, so let's get their input before we move forward with the proposal.

I see a tension between perception and reality. There is clearly a strong 
incentive to look like other vector databases, and in particular adopt the 
{{VECTOR}} data type. But if we create a new type, we are not building on the 
work we have done in the existing {{ARRAY}} type. People use Calcite not for 
its parser but because it deals with the hard parts of query compilation -- in 
particular planning -- with relatively little effort and few surprises.

Perhaps {{VECTOR}} could be syntactic sugar for a fixed-length {{ARRAY}} type? 
(You can use either {{VECTOR}} or {{ARRAY}} in the {{CREATE TABLE}} statement, 
but the columns would appear in the catalog as {{ARRAY}}.)

Are there any places that {{ARRAY}} and {{VECTOR}} are at odds? E.g. do we 
allow {{ORDER BY an_array_column}} and would we want to disallow {{ORDER BY 
a_vector_column}}?

I would be inclined to accept {{VECTOR}} of any element type (as we do for 
{{ARRAY}}) but strongly suggest that people use {{REAL NOT NULL}} and {{TINYINT 
NOT NULL}}, and write implementations of important functions such as 
{{COSINE_SIMILARITY}} only for those types. {{ArrayList<Float>}} would be a 
foolish implementation in Java... a custom {{List}} backed by a {{float[]}} 
seems much more time and memory efficient.


was (Author: julianhyde):
Why a whole new data type? Why not {{ARRAY}} with a constraint?

{code:sql}
CREATE TABLE my_table (
  id INT,
  embedding ARRAY<REAL> CHECK (CARDINALITY(embedding) = 1536)
);
{code}

> Add a VECTOR data type
> ----------------------
>
>                 Key: CALCITE-7857
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7857
>             Project: Calcite
>          Issue Type: New Feature
>          Components: core
>            Reporter: Lantao Jin
>            Priority: Major
>              Labels: pull-request-available
>
> h2. Motivation
> Vector (embedding) search has become a standard database feature, and most 
> SQL engines now have a vector type whose dimension is part of the type: 
> PostgreSQL with pgvector {{vector\(n\)}} (also {{halfvec\(n\)}}, 
> {{bit\(n\)}}), SQL Server 2025 {{VECTOR(n [, float16])}}, Oracle 26ai 
> {{VECTOR(n, FLOAT32|INT8|BINARY)}}, Snowflake {{VECTOR(FLOAT|INT, n)}}, 
> MariaDB, MySQL and TiDB {{VECTOR\(n\)}}, Cassandra 5 {{VECTOR<FLOAT, n>}}, 
> SAP HANA {{REAL_VECTOR\(n\)}}. DuckDB uses fixed-size arrays {{FLOAT[n]}}, 
> and Spark has an open SPIP (SPARK-58787) for {{VECTOR(n, type)}}.
> Calcite has no vector type, and cannot represent an embedding's dimension: 
> {{RelDataTypeFactory.createArrayType(elementType, maxCardinality)}} accepts a 
> cardinality, but {{SqlTypeFactoryImpl.createArrayType}} asserts 
> {{maxCardinality == -1}}, and {{ArraySqlType}} stores only the element type.
> Downstream projects work around this. The OpenSearch SQL plugin's RFC for 
> vector search in PPL on Calcite (opensearch-project/sql#5875) emulates a 
> vector type with a custom {{ArraySqlType}} subclass; the proposed Milvus 
> adapter (CALCITE-7353) maps vector fields to existing types through adapter 
> metadata. Neither can check dimensions during validation, generate the right 
> type in SQL for a database that has a vector type, or give distance functions 
> a precise operand type.
> h2. Proposal
> Add a type {{VECTOR(dimension [, elementType])}}, where {{dimension}} is a 
> positive integer and {{elementType}} is {{REAL}} (4-byte float, the default) 
> or {{TINYINT}} (1-byte integer).
> {code:sql}
> SELECT CAST(ARRAY[1, 2.5, -3] AS VECTOR(3));         -- type VECTOR(3, REAL)
> SELECT CAST('[1, 2.5, -3]' AS VECTOR(3));            -- same value
> SELECT CAST(ARRAY[1, 2, 3] AS VECTOR(3, TINYINT));
> SELECT CAST(v AS REAL ARRAY), CAST(v AS VARCHAR) FROM t;
> -- With the server module's DDL
> CREATE TABLE docs (id INT, embedding VECTOR(768));
> INSERT INTO docs VALUES (1, ARRAY[...]), (2, '[...]'); -- implicit cast on 
> INSERT
> {code}
> h2. Semantics
> # *Type.* New {{SqlTypeName.VECTOR}}, {{SqlTypeFamily.VECTOR}} and class 
> {{VectorSqlType}} (a sibling of {{ArraySqlType}}, not a subclass), created by 
> a new method {{RelDataTypeFactory.createVectorType(elementType, dimension)}}. 
> The type's digest is {{VECTOR(3, REAL)}}; {{getComponentType()}} returns the 
> element type, and {{getPrecision()}} returns the dimension, so JDBC reports 
> the dimension as the column size.
> # *Nullability.* Elements are never null; a vector value as a whole may be 
> null.
> # *Explicit casts.* An {{ARRAY}} of numbers and a {{VECTOR}} cast to each 
> other, element by element. A character string such as {{'[1, 2.5, -3]'}} 
> (numbers separated by commas, in square brackets) casts to a {{VECTOR}}, and 
> a {{VECTOR}} casts to a string in the same format. A {{VECTOR}} casts to a 
> {{VECTOR}} of the same dimension with a different element type. Casts to and 
> from other types (numbers, {{BINARY}}, {{VARIANT}}, {{MULTISET}}, {{MAP}}) 
> are not allowed.
> # *Dimension checks.* If the operand of {{CAST}} is an array constructor or a 
> character literal, a wrong number of elements is a validation error; 
> otherwise it is a run-time error, as is a null element.
> # *Implicit conversions.* None in expressions. A vector can be assigned to a 
> {{VECTOR}} of the same dimension and element type, and {{CASE}}, {{COALESCE}} 
> and {{UNION ALL}} accept vectors of the same dimension and element type. With 
> type coercion, {{INSERT}} and {{UPDATE}} cast an {{ARRAY}}, a character 
> string, or a vector with another element type to the target column's 
> {{VECTOR}} type.
> # *Comparability.* {{VectorSqlType.getComparability()}} returns {{NONE}}, so 
> {{=}}, {{<>}}, {{<}}, {{IS DISTINCT FROM}}, {{NULLIF}}, {{MIN}} and {{MAX}} 
> reject vectors. The validator also rejects vectors as keys of {{ORDER BY}}, 
> {{GROUP BY}}, {{PARTITION BY}}, window {{ORDER BY}}, {{SELECT DISTINCT}}, 
> aggregate {{DISTINCT}}, {{WITHIN DISTINCT}} and {{WITHIN GROUP}}, {{UNION}}, 
> {{INTERSECT}}, {{EXCEPT}} and {{USING}}/{{NATURAL}} joins; {{IN}} and 
> {{BETWEEN}} already reject them. These checks use the type's comparability, 
> so they also apply to user-defined structured types whose comparability is 
> {{NONE}}. SQL Server and Oracle have similar restrictions; pgvector allows 
> ordering and equality. Allowing equality later would be backward-compatible, 
> but disallowing it later would not.
> # *Run time.* As with {{ARRAY}}, a vector is a {{java.util.List}} of its 
> elements; JDBC returns it as a {{java.sql.Array}}.
> # *SQL generation.* The Calcite dialect writes {{VECTOR(n, elementType)}}. 
> The PostgreSQL dialect writes pgvector's {{VECTOR\(n\)}} for {{REAL}} 
> elements. Other dialects throw {{UnsupportedOperationException}}; by default, 
> {{SqlDialect.supportsDataType}} now returns false for {{VECTOR}}.
> # *Serialization.* {{RelJson}} writes a vector type with its {{component}} 
> and {{dimension}}. There are no {{RexLiteral}}s of type {{VECTOR}}; a 
> constant vector is a {{CAST}} of an array constructor.
> h2. Scope
> This issue: the type, parser, validator, casts, Enumerable run time, 
> {{RelJson}}, SQL generation for the Calcite and PostgreSQL dialects, and 
> documentation in {{reference.md}}.
> Follow-up issues:
> * Distance functions, such as {{COSINE_DISTANCE}}, {{L2_DISTANCE}} and 
> {{INNER_PRODUCT}}, in {{SqlLibraryOperators}} for each library (pgvector's 
> {{<->}}, {{<=>}} and {{<#>}} operators, {{VECTOR_DISTANCE}} in SQL Server and 
> Oracle, {{VECTOR_COSINE_SIMILARITY}} in Snowflake), with SQL generation for 
> each dialect.
> * More element types (DOUBLE, half precision, bit vectors), sparse vectors, 
> and a maximum dimension in {{RelDataTypeSystem}}.
> * SQL generation for SQL Server, Oracle, Snowflake, MySQL and MariaDB; 
> mapping of vendor vector types in the JDBC adapter.
> * Casts to and from {{VARIANT}}; element access {{v[i]}} and 
> {{CARDINALITY(v)}} without a cast to {{ARRAY}}.
> * Comparability of a {{ROW}} that contains a vector: {{ROW(v, 1) = ROW(v, 
> 1)}} is not yet rejected, because a record type is always comparable.
> Out of scope: index-aware planning, such as rules that use an 
> approximate-nearest-neighbor index for {{ORDER BY distance LIMIT k}}.
> h2. Open questions
> # Syntax: {{VECTOR(n, type)}} (SQL Server, Oracle, the Spark SPIP), 
> {{VECTOR(type, n)}} (Snowflake), {{VECTOR<type, n>}} (Cassandra), or {{type 
> VECTOR\(n\)}} (by analogy with {{type ARRAY}})?
> # Element type names: Calcite's ({{REAL}}, {{TINYINT}}) or vendor names 
> ({{FLOAT32}}, {{INT8}})? Which element types belong in the first version?
> # Should {{VECTOR}} be a subtype of {{ARRAY}} for coercion, so that array 
> functions accept vectors directly, or stay a distinct type as proposed?
> # Should vectors support equality (comparability {{UNORDERED}}), and 
> therefore {{GROUP BY}} and {{DISTINCT}}, as pgvector does?
> # Should the element type have a default ({{REAL}}), or be required?
> # Should a cast from a string accept {{NaN}} and infinite values? (pgvector 
> rejects them.)
> h2. References
> * pgvector: https://github.com/pgvector/pgvector
> * SQL Server vector data type: 
> https://learn.microsoft.com/en-us/sql/t-sql/data-types/vector-data-type
> * Oracle VECTOR data type: 
> https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/create-tables-using-vector-data-type.html
> * Snowflake VECTOR data type: 
> https://docs.snowflake.com/en/sql-reference/data-types-vector
> * SPARK-58787 (SPIP: VECTOR type)
> * OpenSearch SQL RFC, vector search in PPL: 
> https://github.com/opensearch-project/sql/issues/5875
> * CALCITE-7353 (Milvus adapter)
> * Precedents for a new type: CALCITE-6738 (UUID) and follow-ups CALCITE-6777, 
> CALCITE-6779, CALCITE-6992, CALCITE-7128, CALCITE-7158, CALCITE-7716, 
> CALCITE-7727, CALCITE-7768; CALCITE-4918 (VARIANT)



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to