14 Working with Vectors
Starting with Oracle AI Database Release 26ai, you can declare a table's column as a Vector. A Vector is an array of one or more numeric values that may be integers or fractional numbers.
You can use the Vector data for machine learning. Oracle AI (Artificial Intelligence) Vector Search enables you to query data based on semantics, rather than keywords. For more information about Oracle AI Vector Search, refer to the Oracle AI Vector Search User's Guide.
14.1 JDBC APIs and Types for Vectors
JDBC drivers represent SQL data types as instances of the
java.sql.SQLType interface. For each data type of Oracle Database, the
Oracle JDBC Driver declares an instance of SQLType as a member of
oracle.jdbc.OracleType.
14.1.1 JDBC Types for Vectors
This section describes the new instances of SQLType that are added to the
oracle.jdbc.OracleType enum for Vector support. These instances
represent the VECTOR data type.
Note:
Java object types that can be converted to and from the VECTOR data type are specified in the Java API Reference documentation of each type.- VECTOR
OracleType.VECTORrepresents a Vector of any type, that is, a type with an asterisk (*) wild card.- VECTOR_INT8
OracleType.VECTOR_INT8represents a Vector ofINT8values.- VECTOR_FLOAT32
OracleType.VECTOR_FLOAT32represents a Vector ofFLOAT32values.- VECTOR_FLOAT64
OracleType.VECTOR_FLOAT64represents a Vector ofFLOAT64values.
You must use these type codes when a
PreparedStatement has a Vector type parameter. You can provide
this type as an argument to the setObject(int, Object, SQLType)
method or the setObject(int, Object, int) method. A Vector
parameter cannot be set by calling the setObject(int,
Object) method.
14.1.2 JDBC Interfaces for Vectors
This section describes the JDBC interfaces that have been added or updated for Vector support.
14.1.2.1 The VectorMetaData Interface
The new interface, oracle.jdbc.VectorMetaData stores the
metadata for a Vector column or parameter.
14.1.2.2 The DatabaseMetaData Interface
JDBC drivers represent metadata of tables and stored procedures as instances
of the java.sql.DatabaseMetaData interface.
See Also:
The Java SE Documentation14.1.2.3 The OracleResultSetMetaData and OracleParameterMetaData Interfaces
JDBC drivers represent metadata of columns and parameters as instances of the java.sql.ResultSetMetaData and java.sql.ParameterMetaData interfaces respectively. The Oracle JDBC Driver extends the ResultSetMetaData and ParameterMetaData interfaces with OracleResultSetMetaData and OracleParameterMetaData interfaces, respectively.
14.1.2.4 The SparseArray Interface
Sparse vectors are vectors that typically have a large number of dimensions but with very few non-zero dimension values. For JDBC applications, conversion must happen between the Java objects and the sparse vectors. As Java has no built-in object to represent sparse data, the SparseArray interface is used for this purpose.
The SparseArray interface contains the following sub-interfaces that use a certain Java numeric type to store non-zero values like double, float, byte, and boolean:
SparseDoubleArraySparseFloatArraySparseArraySparseDoubleArray
You can use these sub-interfaces as bind values for the PreparedStatement.setObject(int, Object) method and as return values for the ResultSet.getObject(int, Class) method.
14.1.3 JDBC Methods for Vectors
This section describes the JDBC methods that have been added or updated for Vector support. It also describes the behavior of standard JDBC methods with respect to Vector data.
The getVectorMetaData Method
A method named getVectorMetaData is added to the OracleResultSetMetaData and OracleParameterMetaData interfaces. The method returns an instance of the oracle.jdbc.VectorMetaData interface for a Vector column or parameter, which enables the applications to identify the size and the type of the Vector data at run time. The method returns null for a column or parameter that is not a Vector.
The getLength Method
A method named getLength returns the number of values in a Vector column or parameter. For example:
- The method returns 3 for a column declared as VECTOR(3,
INT8). - The method returns -1 for a Vector column or parameter with a variable length, that is, where asterisk (
*) is specified as the length. For example, VECTOR(*,INT8).
The getArrayClass Method
A method named getArrayClass returns the class of an array object, which you can use in conversions of a Vector column or parameter. For example,
double[].classis returned for a column or parameter that is a Vector of any type. For example, VECTOR(*,*)byte[].classis returned for a column or parameter that is a Vector ofINT8values.float[].classis returned for a column or parameter that is a Vector ofFLOAT32values.double[].classis returned for a column or parameter that is a Vector ofFLOAT64values.
The getType Method
The getType method returns one of the following OracleTypes for a Vector column or parameter:
OracleTypes.VECTORis returned for a column or parameter that is a Vector of any type, that is, a VECTOR(<length>,*) typeOracleTypes.VECTOR_INT8is returned for a column or parameter that is a Vector ofINT8values.OracleTypes.VECTOR_FLOAT32is returned for a column or parameter that is a Vector ofFLOAT32values.OracleTypes.VECTOR_FLOAT64is returned for a column or parameter that is a Vector ofFLOAT64values.
The getColumns Method
The getColumns method retrieves Vector columns in the following ways:
- The
getColumnsmethod returns theintvalue oforacle.jdbc.OracleTypes.VECTOR(-105)as theDATA_TYPEfor a Vector column. - The
getColumnsmethod returns the String value of"VECTOR"as theTYPE_NAMEfor a Vector column.
The getObject(int) or getObject(String) Methods
When you call the getObject(int) or getObject(String) methods of the java.sql.ResultSet interface, there is no default mapping for the VECTOR data type. But, you can choose a default mapping with the oracle.jdbc.vectorDefaultGetObjectType connection property.
The getPrecision and getScale Methods
The getPrecision and getScale methods return 0 for a Vector column or parameter. The JDBC 4.3 Specification does not define the correct behavior of these methods for the VECTOR data type. The return values of 0 indicate that precision and scale are not applicable to the data type. All other methods behave as specified by the JDBC 4.3 Specification.
14.2 SQL to Java Conversions with CallableStatement
JDBC drivers represent procedural SQL calls as instances of the java.sql.CallableStatement interface. The interface defines the registerOutParameter methods that specify the SQL type of an out parameter. A corresponding getObject method is defined, which converts the registered SQL type to a Java object.
See Also:
The CallableStatement InterfaceThis section specifies the conversions of the getObject method, when converting a Vector to a Java object.
Note:
This section does not specify the behavior of thegetObject methods that accept a Class argument. The behavior of these methods is specified in the SQL to Java Conversions with CallableStatment and ResultSet section. These methods are not influenced by a SQL type registered with the registerOutParameter method.
This section discusses the behavior of the widening and narrowing conversions that are possible with Vectors:
OracleType.VECTOR Registrations
The registerOutParameter methods recognize OracleType.VECTOR and OracleTypes.VECTOR. With this registration, the following conversions are performed by the getObject methods, if no Class argument is provided:
- A Vector of
INT8values is converted to abyte[] - A Vector of
FLOAT32values is converted to afloat[] - A Vector of
FLOAT64values is converted to adouble[]
OracleType.VECTOR_INT8 Registrations
The registerOutParameter methods recognize OracleType.VECTOR_INT8 and OracleTypes.VECTOR_INT8. With this registration, the following conversions are performed by the getObject methods, if no Class argument is provided:
- A Vector of
INT8values is converted to abyte[]. No additional conversion occurs in this case. - A Vector of
FLOAT32values is converted to abyte[], where, a widening conversion ofbytetofloatoccurs.
OracleType.VECTOR_FLOAT32 Registrations
The registerOutParameter methods recognize OracleType.VECTOR_FLOAT32 and OracleTypes.VECTOR_FLOAT31. With this registration, the following conversions are performed by the getObject methods, if no Class argument is provided:
- A Vector of
INT8values is converted to afloat[], where, a widening conversion ofbytetofloatoccurs. - A Vector of
FLOAT32values is converted to afloat[]. No additional conversion occurs in this case. - A Vector of
FLOAT64values is converted to afloat[], where, a narrowing conversion ofdoubletofloatoccurs.
OracleType.VECTOR_FLOAT64 Registrations
The registerOutParameter methods recognize OracleType.VECTOR_FLOAT64 and OracleTypes.VECTOR_FLOAT64. With this registration, the following conversions are performed by the getObject methods, if no Class argument is provided:
- A Vector of
INT8values is converted to adouble[], where, a widening conversion ofbytetodoubleoccurs. - A Vector of
FLOAT32values is converted to adouble[], where, a widening conversion offloattodoubleoccurs. - A Vector of
FLOAT64values is converted to adouble[]. No additional conversion occurs in this case.
14.3 SQL to Java Conversions with CallableStatment and ResultSet
JDBC drivers represent the values of out parameters and columns as instances of the java.sql.CallableStatement and java.sql.ResultSet interfaces respectively. Both the interfaces define getObject methods that convert a SQL type to a Java object.
This section describes the behavior of the getObject methods, when converting Vector parameters and columns to Java objects.
This section discusses the behavior of the widening and narrowing conversions that are possible with Vectors:
Default Conversions
The getObject(int) and getObject(String) methods of the ResultSet interface do not support conversions of Vector columns. The JDBC 4.3 Specification does not specify any class of Java object as the default conversion of Vector.
The getObject(int) and getObject(String) methods of the CallableStatement interface support conversions of Vector columns. Refer to the SQL to Java Conversions with CallableStatement section for more details.
boolean[] Conversions
The getObject methods recognize boolean[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted toboolean[]. A value of 0 is converted tofalse, and a value that is not 0, is converted totrue. - A Vector of
FLOAT32values is converted toboolean[]. A value of 0.0 is converted tofalse, and a value that is not 0.0, is converted totrue. - A Vector of
FLOAT64values is converted toboolean[]. A value of 0.0 is converted tofalse, and a value that is not 0.0, is converted totrue.
byte[] Conversions
The getObject methods recognize byte[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted tobyte[]. No additional conversion is performed in this case. - A Vector of
FLOAT32values is converted tobyte[], where, a narrowing conversion offloattobyteoccurs. - A Vector of
FLOAT64values is converted tobyte[], where, a narrowing conversion ofdoubletobyteoccurs.
short[] Conversions
The getObject methods recognize short[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted toshort[], where, a widening conversion ofbytetoshortoccurs. - A Vector of
FLOAT32values is converted toshort[], where, a narrowing conversion offloattoshortoccurs. - A Vector of
FLOAT64values is converted toshort[], where, a narrowing conversion ofdoubletoshortoccurs.
int[] Conversions
The getObject methods recognize int[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted toint[], where, a widening conversion ofbytetointoccurs. - A Vector of
FLOAT32values is converted toint[], where, a narrowing conversion offloattointoccurs. - A Vector of
FLOAT64values is converted tobyte[], where, a narrowing conversion ofdoubletointoccurs.
long[] Conversions
The getObject methods recognize long[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted tolong[], where, a widening conversion ofbytetolongoccurs. - A Vector of
FLOAT32values is converted tolong[], where, a narrowing conversion offloattolongoccurs. - A Vector of
FLOAT64values is converted tolong[], where, a narrowing conversion ofdoubletolongoccurs.
float[] Conversions
The getObject methods recognize float[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted tofloat[], where, a widening conversion ofbytetointoccurs. - A Vector of
FLOAT32values is converted tofloat[]. No additional conversion is performed in this case. - A Vector of
FLOAT64values is converted tofloat[], where, a narrowing conversion ofdoubletofloatoccurs.
double[] Conversions
The getObject methods recognize double[].class as a target Java type. The following conversions are performed:
- A Vector of
INT8values is converted todouble[], where, a widening conversion ofbytetodoubleoccurs. - A Vector of
FLOAT32values is converted todouble[], where, a widening conversion offloattodoubleoccurs. - A Vector of
FLOAT64values is converted todouble[], where, a narrowing conversion ofdoubletofloatoccurs.
14.4 Java to SQL Conversions with PreparedStatement and CallableStatement
JDBC drivers represent SQL commands as instances of the
java.sql.PreparedStatement and
java.sql.CallableStatement interfaces. These interfaces define the
setObject methods that convert a Java object to a SQL type. This
section describes the behavior of the setObject method, when converting
Java objects to a Vector.
This section discusses the behavior of the widening and narrowing conversions that are possible with Vectors:
Default Conversion
The setObject(int, Object) method does not support conversions to Vectors. The JDBC 4.3 Specification does not specify Vector as the default conversion for any class of Java object.
OracleType.VECTOR Conversions
The setObject methods recognize OracleType.VECTOR and OracleTypes.VECTOR as a target SQL type. The following conversions are supported for this type:
- A
byte[]is converted to a Vector ofINT8values - A
float[]is converted to a Vector ofFLOAT32values - A
double[]is converted to a Vector ofFLOAT64values.
OracleType.VECTOR_INT8 Conversions
The setObject methods recognize OracleType.VECTOR_INT8 and OracleTypes.VECTOR_INT8 as a target SQL type. The following conversions are supported for this target SQL type:
- A
boolean[]is converted to a Vector ofINT8values. A boolean value offalseis converted to 0, and a value oftrueis converted to 1. - A
byte[]is converted to a Vector ofINT8values. No additional conversion occurs in this case. - A
short[]is converted to a Vector ofINT8values, where, a narrowing conversion ofshorttobyteoccurs. - An
int[]is converted to a Vector ofINT8values, where, a narrowing conversion ofinttobyteoccurs. - A
long[]is converted to a Vector ofINT8values, where, a narrowing conversion oflongtobyteoccurs. - A
float[]is converted to a Vector ofINT8values, where, a narrowing conversion offloattobyteoccurs. - A
double[]is converted to a Vector ofINT8values, where, a narrowing conversion ofdoubletobyteoccurs.
OracleType.VECTOR_FLOAT32 Conversions
The setObject methods recognize OracleType.VECTOR_FLOAT32 and OracleTypes.VECTOR_FLOAT32 as a target SQL type. The following conversions are supported for this target SQL type:
- A
boolean[]is converted to a Vector ofFLOAT32values. A boolean value offalseis converted to 0.0, and a value oftrueis converted to 1.0. - A
byte[]is converted to a Vector ofFLOAT32values, where, a widening conversion ofbytetofloatoccurs. - A
short[]is converted to a Vector ofFLOAT32values, where, a widening conversion ofshorttofloatoccurs. - An
int[]is converted to a Vector ofFLOAT32values, where, a widening conversion ofinttofloatoccurs. - A
long[]is converted to a Vector ofFLOAT32values, where, a widening conversion oflongtofloatoccurs. - A
float[]is converted to a Vector ofFLOAT32values. No additional conversion occurs in this case. - A
double[]is converted to a Vector ofFLOAT32values, where, a narrowing conversion ofdoubletofloatoccurs.
OracleType.VECTOR_FLOAT64 Conversions
The setObject methods recognize OracleType.VECTOR_FLOAT64 and OracleTypes.VECTOR_FLOAT64 as a target SQL type. The following conversions are supported for this target SQL type:
- A
boolean[]is converted to a Vector ofFLOAT64values, where, a boolean value offalseis converted to 0.0 andtrueis converted to 1.0. - A
byte[]is converted to a Vector ofFLOAT64values, where, a widening conversion ofbytetodoubleoccurs. - A
short[]is converted to a Vector ofFLOAT64values, where, a widening conversion ofshorttodoubleoccurs. - An
int[]is converted to a Vector ofFLOAT64values, where, a widening conversion ofinttodoubleoccurs. - A
long[]is converted to a Vector ofFLOAT64values, where, a widening conversion oflongtodoubleoccurs. - A
float[]is converted to a Vector ofFLOAT64values, where, a widening conversion offloattodoubleoccurs. - A
double[]is converted to a Vector ofFLOAT64values. No additional conversion occurs in this case.
14.5 The VECTOR Datum Class
The oracle.sql package defines a Datum class with subclasses that represent each Oracle SQL data type. For example, the oracle.sql.NUMBER subclass represents a value of the NUMBER data type, and oracle.sql.TIMESTAMP represents values of the TIMESTAMP data type.
A new subclass oracle.sql.VECTOR is added to the Datum class to represent values of Vector columns. The VECTOR class supports conversions between Java objects and Oracle's binary encoding of a Vector.
Conversions from Java Objects
The VECTOR class defines factory methods that create an instance of a Vector. These factory methods convert a Java object into the binary encoding of a Vector in the following ways:
- An
ofFloat64Values(Object)method converts a Java object into a Vector ofFLOAT64values. - An
ofFloat32Values(Object)method converts a Java object into a Vector ofFLOAT32values. - An
ofInt8Values(Object)method converts a Java object into a Vector ofINT8values.
Conversions to Java Objects
The VECTOR class defines instance methods that return a Java object representation of a Vector. These instance methods convert the binary encoding of a Vector into a Java object in the following ways:
- The
toBooleanArray()method converts a Vector into an array ofbooleanvalues - The
toByteArray()method converts a Vector into an array ofbytevalues - The
toShortArray()method converts a Vector into an array ofshortvalues - The
toIntArray()method converts a Vector into an array ofintvalues - The
toLongArray()method converts a Vector into an array oflongvalues - The
toFloatArray()method converts a Vector into an array offloatvalues - The
toDoubleArray()method converts a Vector into an array ofdoublevalues
14.6 Backward Compatibility with Earlier JDBC Drivers
Earlier releases of Oracle JDBC may connect to an Oracle AI Database 26ai. These JDBC builds do not have built-in support for the VECTOR data type, but they do support the VARCHAR and CLOB data types, and applications may use these types for DML and query operations on Vector columns.
JDBC supports conversions of String with VARCHAR and java.sql.Clob with CLOB. These conversions have consistent behavior in Oracle Database 19c, 21c, and 26ai releases.
The following code example demonstrates these conversions, where a String and java.sql.Clob are passed to the PreparedStatement.setObject method. Conversions of CLOB to String are demonstrated by calling the ResultSet.getObject(int, Class) method with the String.class method.
import oracle.jdbc.OracleStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Arrays;
import java.util.Random;
/**
* This example can be run with 19.x releases of Oracle JDBC. It uses String to
* represent VECTOR data, which may be suitable for database tools.
*/
public class VectorStringTest {
public static void main(String[] args) throws SQLException {
try (
Connection connection =
DriverManager.getConnection("jdbc:oracle:thin:@test");
Table table = new Table(connection);
PreparedStatement insert = connection.prepareStatement(
"INSERT INTO vector_test(id, value) VALUES (?, ?)");
PreparedStatement query = connection.prepareStatement(
"SELECT id, value FROM vector_test ORDER BY id")) {
// Toy example to show the VARCHAR literal syntax of a VECTOR: A comma
// separated numbers enclosed in square brackets.
String vectorLiteral = "[0.1, 0.2, 0.3]";
insert.setString(1, "0");
insert.setString(2, vectorLiteral);
System.out.println("Inserting VECTOR (VARCHAR):\n\t" + vectorLiteral);
insert.executeUpdate();
// Generate a Vector of 256 dimensions, each having many decimal point
// digits. Arrays.toString(double[]) conveniently generates the Vector
// literal syntax, so it may be used to convert the Vector to String.
double[] vector = getVector(256);
String vectorString = Arrays.toString(vector);
insert.setObject(1, "1");
insert.setObject(2, vectorString);
System.out.println("Inserting VECTOR (VARCHAR):\n\t" + vectorString);
insert.executeUpdate();
// If the String is longer than 32k characters, then it must be converted
// to a CLOB (32k is the maximum length of a VARCHAR).
// This example results in:
// ORA-42552: VECTOR() library processing error 'LVECTOR_ERR_INPUT_NAN_OR_INF' in 'qvcCons:lvector_from_oratext'.
// The 2048 length is commented out for this reason. A 256 length is used
// just to demonstrate the conversion to CLOB.
// double[] largeVector = getVector(2048);
double[] largeVector = getVector(256);
Clob vectorClob = connection.createClob();
try {
String largeVectorString = Arrays.toString(largeVector);
vectorClob.setString(1L, largeVectorString);
insert.setString(1, "2");
insert.setObject(2, vectorClob);
System.out.println("Inserting VECTOR (CLOB):\n\t" + largeVectorString);
insert.executeUpdate();
}
finally {
vectorClob.free();
}
// Query the VECTOR column. For a 19c JDBC client, the database sends the
// VECTOR as a CLOB. For a 26ai JDBC client, it sends it as the VECTOR binary
// encoding. When the getString method has JDBC convert the VECTOR, both
// client versions should return the same text value.
try (ResultSet resultSet = query.executeQuery()) {
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()) {
System.out.println("Queried VECTOR:");
System.out.printf(
"\t%s (%s) : %s%n",
metaData.getColumnName(1),
metaData.getColumnTypeName(1),
resultSet.getString(1));
System.out.printf(
"\t%s (%s) : %s%n",
metaData.getColumnName(2),
metaData.getColumnTypeName(2),
resultSet.getString(2));
}
}
// Applications can request that the database always sends the VECTOR
// as a CLOB. The defineColumnType method is used to specify the CLOB
// type.
System.out.println("\nQuerying VECTOR as CLOB");
query.unwrap(OracleStatement.class)
.defineColumnType(2, Types.CLOB);
try (ResultSet resultSet = query.executeQuery()) {
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()) {
System.out.println("Queried VECTOR:");
System.out.printf(
"\t%s (%s) : %s%n",
metaData.getColumnName(1),
metaData.getColumnTypeName(1),
resultSet.getString(1));
System.out.printf(
"\t%s (%s) : %s%n",
metaData.getColumnName(2),
metaData.getColumnTypeName(2),
resultSet.getString(2));
}
}
}
}
static double[] getVector(int length) {
return new Random(0).doubles()
.limit(length)
.toArray();
}
static class Table implements AutoCloseable {
private final Connection connection;
Table(Connection connection) throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.addBatch("DROP TABLE IF EXISTS vector_test");
statement.addBatch(
"CREATE TABLE vector_test" +
" (id NUMBER PRIMARY KEY, value VECTOR(*,*))");
statement.executeBatch();
}
this.connection = connection;
}
@Override
public void close() throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.execute("DROP TABLE IF EXISTS vector_test");
}
}
}
}