14 Working with Vectors
Starting with Oracle Database Release 23ai, 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.VECTOR
represents a Vector of any type, that is, a type with an asterisk (*
) wild card.- VECTOR_INT8
OracleType.VECTOR_INT8
represents a Vector ofINT8
values.- VECTOR_FLOAT32
OracleType.VECTOR_FLOAT32
represents a Vector ofFLOAT32
values.- VECTOR_FLOAT64
OracleType.VECTOR_FLOAT64
represents a Vector ofFLOAT64
values.
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
:
SparseDoubleArray
SparseFloatArray
SparseArray
SparseDoubleArray
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[].class
is returned for a column or parameter that is a Vector of any type. For example, VECTOR(*
,*
)byte[].class
is returned for a column or parameter that is a Vector ofINT8
values.float[].class
is returned for a column or parameter that is a Vector ofFLOAT32
values.double[].class
is returned for a column or parameter that is a Vector ofFLOAT64
values.
The getType Method
The getType
method returns one of the following OracleTypes
for a Vector column or parameter:
OracleTypes.VECTOR
is returned for a column or parameter that is a Vector of any type, that is, a VECTOR(<length>,*) typeOracleTypes.VECTOR_INT8
is returned for a column or parameter that is a Vector ofINT8
values.OracleTypes.VECTOR_FLOAT32
is returned for a column or parameter that is a Vector ofFLOAT32
values.OracleTypes.VECTOR_FLOAT64
is returned for a column or parameter that is a Vector ofFLOAT64
values.
The getColumns Method
The getColumns
method retrieves Vector columns in the following ways:
- The
getColumns
method returns theint
value oforacle.jdbc.OracleTypes.VECTOR
(-105)
as theDATA_TYPE
for a Vector column. - The
getColumns
method returns the String value of"VECTOR"
as theTYPE_NAME
for 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
INT8
values is converted to abyte[]
- A Vector of
FLOAT32
values is converted to afloat[]
- A Vector of
FLOAT64
values 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
INT8
values is converted to abyte[]
. No additional conversion occurs in this case. - A Vector of
FLOAT32
values is converted to abyte[]
, where, a widening conversion ofbyte
tofloat
occurs.
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
INT8
values is converted to afloat[]
, where, a widening conversion ofbyte
tofloat
occurs. - A Vector of
FLOAT32
values is converted to afloat[]
. No additional conversion occurs in this case. - A Vector of
FLOAT64
values is converted to afloat[]
, where, a narrowing conversion ofdouble
tofloat
occurs.
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
INT8
values is converted to adouble[]
, where, a widening conversion ofbyte
todouble
occurs. - A Vector of
FLOAT32
values is converted to adouble[]
, where, a widening conversion offloat
todouble
occurs. - A Vector of
FLOAT64
values 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
INT8
values is converted toboolean[]
. A value of 0 is converted tofalse
, and a value that is not 0, is converted totrue
. - A Vector of
FLOAT32
values 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
FLOAT64
values 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
INT8
values is converted tobyte[]
. No additional conversion is performed in this case. - A Vector of
FLOAT32
values is converted tobyte[]
, where, a narrowing conversion offloat
tobyte
occurs. - A Vector of
FLOAT64
values is converted tobyte[]
, where, a narrowing conversion ofdouble
tobyte
occurs.
short[] Conversions
The getObject
methods recognize short[].class
as a target Java type. The following conversions are performed:
- A Vector of
INT8
values is converted toshort[]
, where, a widening conversion ofbyte
toshort
occurs. - A Vector of
FLOAT32
values is converted toshort[]
, where, a narrowing conversion offloat
toshort
occurs. - A Vector of
FLOAT64
values is converted toshort[]
, where, a narrowing conversion ofdouble
toshort
occurs.
int[] Conversions
The getObject
methods recognize int[].class
as a target Java type. The following conversions are performed:
- A Vector of
INT8
values is converted toint[]
, where, a widening conversion ofbyte
toint
occurs. - A Vector of
FLOAT32
values is converted toint[]
, where, a narrowing conversion offloat
toint
occurs. - A Vector of
FLOAT64
values is converted tobyte[]
, where, a narrowing conversion ofdouble
toint
occurs.
long[] Conversions
The getObject
methods recognize long[].class
as a target Java type. The following conversions are performed:
- A Vector of
INT8
values is converted tolong[]
, where, a widening conversion ofbyte
tolong
occurs. - A Vector of
FLOAT32
values is converted tolong[]
, where, a narrowing conversion offloat
tolong
occurs. - A Vector of
FLOAT64
values is converted tolong[]
, where, a narrowing conversion ofdouble
tolong
occurs.
float[] Conversions
The getObject
methods recognize float[].class
as a target Java type. The following conversions are performed:
- A Vector of
INT8
values is converted tofloat[]
, where, a widening conversion ofbyte
toint
occurs. - A Vector of
FLOAT32
values is converted tofloat[]
. No additional conversion is performed in this case. - A Vector of
FLOAT64
values is converted tofloat[]
, where, a narrowing conversion ofdouble
tofloat
occurs.
double[] Conversions
The getObject
methods recognize double[].class
as a target Java type. The following conversions are performed:
- A Vector of
INT8
values is converted todouble[]
, where, a widening conversion ofbyte
todouble
occurs. - A Vector of
FLOAT32
values is converted todouble[]
, where, a widening conversion offloat
todouble
occurs. - A Vector of
FLOAT64
values is converted todouble[]
, where, a narrowing conversion ofdouble
tofloat
occurs.
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 ofINT8
values - A
float[]
is converted to a Vector ofFLOAT32
values - A
double[]
is converted to a Vector ofFLOAT64
values.
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 ofINT8
values. A boolean value offalse
is converted to 0, and a value oftrue
is converted to 1. - A
byte[]
is converted to a Vector ofINT8
values. No additional conversion occurs in this case. - A
short[]
is converted to a Vector ofINT8
values, where, a narrowing conversion ofshort
tobyte
occurs. - An
int[]
is converted to a Vector ofINT8
values, where, a narrowing conversion ofint
tobyte
occurs. - A
long[]
is converted to a Vector ofINT8
values, where, a narrowing conversion oflong
tobyte
occurs. - A
float[]
is converted to a Vector ofINT8
values, where, a narrowing conversion offloat
tobyte
occurs. - A
double[]
is converted to a Vector ofINT8
values, where, a narrowing conversion ofdouble
tobyte
occurs.
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 ofFLOAT32
values. A boolean value offalse
is converted to 0.0, and a value oftrue
is converted to 1.0. - A
byte[]
is converted to a Vector ofFLOAT32
values, where, a widening conversion ofbyte
tofloat
occurs. - A
short[]
is converted to a Vector ofFLOAT32
values, where, a widening conversion ofshort
tofloat
occurs. - An
int[]
is converted to a Vector ofFLOAT32
values, where, a widening conversion ofint
tofloat
occurs. - A
long[]
is converted to a Vector ofFLOAT32
values, where, a widening conversion oflong
tofloat
occurs. - A
float[]
is converted to a Vector ofFLOAT32
values. No additional conversion occurs in this case. - A
double[]
is converted to a Vector ofFLOAT32
values, where, a narrowing conversion ofdouble
tofloat
occurs.
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 ofFLOAT64
values, where, a boolean value offalse
is converted to 0.0 andtrue
is converted to 1.0. - A
byte[]
is converted to a Vector ofFLOAT64
values, where, a widening conversion ofbyte
todouble
occurs. - A
short[]
is converted to a Vector ofFLOAT64
values, where, a widening conversion ofshort
todouble
occurs. - An
int[]
is converted to a Vector ofFLOAT64
values, where, a widening conversion ofint
todouble
occurs. - A
long[]
is converted to a Vector ofFLOAT64
values, where, a widening conversion oflong
todouble
occurs. - A
float[]
is converted to a Vector ofFLOAT64
values, where, a widening conversion offloat
todouble
occurs. - A
double[]
is converted to a Vector ofFLOAT64
values. 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 ofFLOAT64
values. - An
ofFloat32Values(Object)
method converts a Java object into a Vector ofFLOAT32
values. - An
ofInt8Values(Object)
method converts a Java object into a Vector ofINT8
values.
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 ofboolean
values - The
toByteArray()
method converts a Vector into an array ofbyte
values - The
toShortArray()
method converts a Vector into an array ofshort
values - The
toIntArray()
method converts a Vector into an array ofint
values - The
toLongArray()
method converts a Vector into an array oflong
values - The
toFloatArray()
method converts a Vector into an array offloat
values - The
toDoubleArray()
method converts a Vector into an array ofdouble
values
14.6 Backward Compatibility with Earlier JDBC Drivers
Earlier releases of Oracle JDBC may connect to an Oracle Database 23ai. 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 23ai 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 23ai 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");
}
}
}
}