Skip to content

Commit db8173c

Browse files
committed
HHH-19705 Add vector support for DB2
1 parent 3c05976 commit db8173c

File tree

66 files changed

+865
-146
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+865
-146
lines changed

docker_db.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ db2_11_5() {
306306

307307
db2_12_1() {
308308
$PRIVILEGED_CLI $CONTAINER_CLI rm -f db2 || true
309-
$PRIVILEGED_CLI $CONTAINER_CLI run --name db2 --privileged -e DB2INSTANCE=orm_test -e DB2INST1_PASSWORD=orm_test -e DBNAME=orm_test -e LICENSE=accept -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e TO_CREATE_SAMPLEDB=false -e REPODB=false -p 50000:50000 -d ${DB_IMAGE_DB2_11_5:-icr.io/db2_community/db2:12.1.2.0}
309+
$PRIVILEGED_CLI $CONTAINER_CLI run --name db2 --privileged --platform=linux/amd64 -e DB2INSTANCE=orm_test -e DB2INST1_PASSWORD=orm_test -e DBNAME=orm_test -e LICENSE=accept -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e TO_CREATE_SAMPLEDB=false -e REPODB=false -e IS_OSXFS=true -e BLU=false -e ENABLE_ORACLE_COMPATIBILITY=false -e UPDATEAVAIL=NO -e PERSISTENT_HOME=false -e HADR_ENABLED=false -p 50000:50000 -d ${DB_IMAGE_DB2_12_1:-icr.io/db2_community/db2:12.1.2.0}
310310
# Give the container some time to start
311311
OUTPUT=
312312
while [[ $OUTPUT != *"INSTANCE"* ]]; do

documentation/src/main/asciidoc/userguide/chapters/query/extensions/Vector.adoc

Lines changed: 116 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,25 @@ so no further configuration is necessary to make the features available.
5353
[[vector-module-usage]]
5454
==== Usage
5555

56-
Annotate a persistent attribute with `@JdbcTypeCode(SqlTypes.VECTOR)` and specify the vector length with `@Array(length = ...)`.
56+
Annotate a persistent attribute with one of the various vector type codes `@JdbcTypeCode` and specify the vector length with `@Array(length = ...)`.
57+
Possible vector type codes and the compatible Java types are:
58+
59+
* `@JdbcTypeCode(SqlTypes.VECTOR_BINARY)` for `byte[]`
60+
* `@JdbcTypeCode(SqlTypes.VECTOR_INT8)` for `byte[]`
61+
* `@JdbcTypeCode(SqlTypes.VECTOR_FLOAT16)` for `float[]`
62+
* `@JdbcTypeCode(SqlTypes.VECTOR_FLOAT32)` for `float[]`
63+
* `@JdbcTypeCode(SqlTypes.VECTOR_FLOAT64)` for `double[]`
64+
* `@JdbcTypeCode(SqlTypes.VECTOR)` for `float[]`
65+
66+
Hibernate ORM also provides support for sparse vectors through dedicated Java types:
67+
68+
* `@JdbcTypeCode(SqlTypes.SPARSE_VECTOR_INT8)` for `SparseByteVector`
69+
* `@JdbcTypeCode(SqlTypes.SPARSE_VECTOR_FLOAT32)` for `SparseFloatVector`
70+
* `@JdbcTypeCode(SqlTypes.SPARSE_VECTOR_FLOAT64)` for `SparseDoubleVector`
5771

5872
[WARNING]
5973
====
60-
As Oracle AI Vector Search supports different types of elements (to ensure better performance and compatibility with embedding models), you can also use:
61-
62-
- `@JdbcTypeCode(SqlTypes.VECTOR_INT8)` for `byte[]`
63-
- `@JdbcTypeCode(SqlTypes.VECTOR_FLOAT32)` for `float[]`
64-
- `@JdbcTypeCode(SqlTypes.VECTOR_FLOAT64)` for `double[]`.
74+
Vector data type support depends on native support of the underlying database.
6575
====
6676

6777
[[vector-module-usage-example]]
@@ -88,14 +98,21 @@ Expressions of the vector type can be used with various vector functions.
8898
| `euclidean_distance()` | Computes the https://en.wikipedia.org/wiki/Euclidean_distance[euclidean distance] between two vectors. Maps to the `<``-``>` operator for `pgvector` and maps to the
8999
`vector_distance(v1, v2, EUCLIDEAN)` function for `Oracle AI Vector Search`.
90100

101+
| `euclidean_squared_distance()` | Computes the https://en.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance[squared euclidean distance] between two vectors.
102+
91103
| `l2_distance()` | Alias for `euclidean_distance()`
92104

105+
| `l2_squared_distance()` | Alias for `euclidean_squared_distance()`
106+
93107
| `taxicab_distance()` | Computes the https://en.wikipedia.org/wiki/Taxicab_geometry[taxicab distance] between two vectors. Maps to `vector_distance(v1, v2, MANHATTAN)` function for `Oracle AI Vector Search`.
94108

95109
| `l1_distance()` | Alias for `taxicab_distance()`
96110

97111
| `hamming_distance()` | Computes the https://en.wikipedia.org/wiki/Hamming_distance[hamming distance] between two vectors. Maps to `vector_distance(v1, v2, HAMMING)` function for `Oracle AI Vector Search`.
98112

113+
| `jaccard_distance()` | Computes the https://en.wikipedia.org/wiki/Jaccard_index[jaccard distance] between two vectors. Maps to the `<``%``>` operator for `pgvector` and maps to the
114+
`vector_distance(v1, v2, JACCARD)` function for `Oracle AI Vector Search`.
115+
99116
| `inner_product()` | Computes the https://en.wikipedia.org/wiki/Inner_product_space[inner product] between two vectors
100117

101118
| `negative_inner_product()` | Computes the negative inner product. Maps to the `<``#``>` operator for `pgvector` and maps to the
@@ -104,6 +121,14 @@ Expressions of the vector type can be used with various vector functions.
104121
| `vector_dims()` | Determines the dimensions of a vector
105122

106123
| `vector_norm()` | Computes the https://en.wikipedia.org/wiki/Euclidean_space#Euclidean_norm[Euclidean norm] of a vector
124+
125+
| `l2_norm()` | Alias for `vector_norm()`
126+
127+
| `l2_normalize()` | Normalizes each component of a vector by dividing it with the https://en.wikipedia.org/wiki/Euclidean_space#Euclidean_norm[Euclidean norm] of the vector.
128+
129+
| `binary_quantize()` | Reduces a vector of size N to a binary vector with N bits, using 0 for values <= 0 and 1 for values > 0.
130+
131+
| `subvector()` | Creates a subvector from a given vector, a 1-based start index and a count.
107132
|===
108133

109134
In addition to these special vector functions, it is also possible to use vectors with the following builtin `pgvector` operators:
@@ -143,6 +168,21 @@ include::{example-dir-vector}/FloatVectorTest.java[tags=euclidean-distance-examp
143168
----
144169
====
145170

171+
[[vector-module-functions-euclidean-squared-distance]]
172+
===== `euclidean_squared_distance()` and `l2_squared_distance()`
173+
174+
Computes the https://en.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance[squared euclidean distance] between two vectors,
175+
which is `sum( (v1_i - v2_i)^2 )`, just like the regular `euclidean_distance`, but without the `sqrt`.
176+
The `l2_squared_distance()` function is an alias.
177+
178+
[[vector-module-functions-euclidean-squared-distance-example]]
179+
====
180+
[source, java, indent=0]
181+
----
182+
include::{example-dir-vector}/FloatVectorTest.java[tags=euclidean-squared-distance-example]
183+
----
184+
====
185+
146186
[[vector-module-functions-taxicab-distance]]
147187
===== `taxicab_distance()` and `l1_distance()`
148188

@@ -158,6 +198,36 @@ include::{example-dir-vector}/FloatVectorTest.java[tags=taxicab-distance-example
158198
----
159199
====
160200

201+
[[vector-module-functions-hamming-distance]]
202+
===== `hamming_distance()`
203+
204+
Computes the https://en.wikipedia.org/wiki/Hamming_distance[hamming distance] between two binary vectors,
205+
which is `bit_count(v1 ^ v2)` i.e. the amount of bits where two vectors differ.
206+
Maps to the `<``~``>` operator for `pgvector`.
207+
208+
[[vector-module-functions-taxicab-distance-example]]
209+
====
210+
[source, java, indent=0]
211+
----
212+
include::{example-dir-vector}/BinaryVectorTest.java[tags=hamming-distance-example]
213+
----
214+
====
215+
216+
[[vector-module-functions-jaccard-distance]]
217+
===== `jaccard_distance()`
218+
219+
Computes the https://en.wikipedia.org/wiki/Jaccard_index[jaccard distance] between two binary vectors,
220+
which is `1 - bit_count(v1 & v2) / bit_count(v1 | v2)`.
221+
Maps to the `<``%``>` operator for `pgvector`.
222+
223+
[[vector-module-functions-taxicab-distance-example]]
224+
====
225+
[source, java, indent=0]
226+
----
227+
include::{example-dir-vector}/BinaryVectorTest.java[tags=jaccard-distance-example]
228+
----
229+
====
230+
161231
[[vector-module-functions-inner-product]]
162232
===== `inner_product()` and `negative_inner_product()`
163233

@@ -187,10 +257,11 @@ include::{example-dir-vector}/FloatVectorTest.java[tags=vector-dims-example]
187257
====
188258

189259
[[vector-module-functions-vector-norm]]
190-
===== `vector_norm()`
260+
===== `vector_norm()` and `l2_norm()`
191261

192262
Computes the https://en.wikipedia.org/wiki/Euclidean_space#Euclidean_norm[Euclidean norm] of a vector,
193263
which is `sqrt( sum( v_i^2 ) )`.
264+
The `l2_norm()` function is an alias.
194265

195266
[[vector-module-functions-vector-norm-example]]
196267
====
@@ -200,6 +271,44 @@ include::{example-dir-vector}/FloatVectorTest.java[tags=vector-norm-example]
200271
----
201272
====
202273

274+
[[vector-module-functions-l2-normalize]]
275+
===== `l2_normalize()`
276+
277+
Normalizes each component of a vector by dividing it with the https://en.wikipedia.org/wiki/Euclidean_space#Euclidean_norm[Euclidean norm] of the vector.
278+
279+
[[vector-module-functions-l2-normalize-example]]
280+
====
281+
[source, java, indent=0]
282+
----
283+
include::{example-dir-vector}/FloatVectorTest.java[tags=l2-normalize-example]
284+
----
285+
====
286+
287+
[[vector-module-functions-binary-quantize]]
288+
===== `binary_quantize()`
289+
290+
Reduces a vector of size N to a binary vector with N bits, using 0 for values <= 0 and 1 for values > 0.
291+
292+
[[vector-module-functions-binary-quantize-example]]
293+
====
294+
[source, java, indent=0]
295+
----
296+
include::{example-dir-vector}/FloatVectorTest.java[tags=binary-quantize-example]
297+
----
298+
====
299+
300+
[[vector-module-functions-subvector]]
301+
===== `binary_quantize()`
302+
303+
Creates a subvector from a given vector, a 1-based start index and a count.
304+
305+
[[vector-module-functions-subvector-example]]
306+
====
307+
[source, java, indent=0]
308+
----
309+
include::{example-dir-vector}/FloatVectorTest.java[tags=subvector-example]
310+
----
311+
====
203312

204313

205314

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBCastingInetJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import java.sql.ResultSet;
1111
import java.sql.SQLException;
1212

13+
import org.checkerframework.checker.nullness.qual.Nullable;
1314
import org.hibernate.dialect.Dialect;
15+
import org.hibernate.engine.jdbc.Size;
1416
import org.hibernate.sql.ast.spi.SqlAppender;
1517
import org.hibernate.type.SqlTypes;
1618
import org.hibernate.type.descriptor.ValueBinder;
@@ -35,6 +37,7 @@ public class GaussDBCastingInetJdbcType implements JdbcType {
3537
@Override
3638
public void appendWriteExpression(
3739
String writeExpression,
40+
@Nullable Size size,
3841
SqlAppender appender,
3942
Dialect dialect) {
4043
appender.append( "cast(" );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBCastingIntervalSecondJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import java.sql.ResultSet;
1111
import java.sql.SQLException;
1212

13+
import org.checkerframework.checker.nullness.qual.Nullable;
1314
import org.hibernate.dialect.Dialect;
15+
import org.hibernate.engine.jdbc.Size;
1416
import org.hibernate.engine.spi.SessionFactoryImplementor;
1517
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
1618
import org.hibernate.sql.ast.SqlAstTranslator;
@@ -77,6 +79,7 @@ public JdbcMappingContainer getExpressionType() {
7779
@Override
7880
public void appendWriteExpression(
7981
String writeExpression,
82+
@Nullable Size size,
8083
SqlAppender appender,
8184
Dialect dialect) {
8285
appender.append( '(' );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBCastingJsonArrayJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
*/
55
package org.hibernate.community.dialect;
66

7+
import org.checkerframework.checker.nullness.qual.Nullable;
78
import org.hibernate.dialect.Dialect;
9+
import org.hibernate.engine.jdbc.Size;
810
import org.hibernate.sql.ast.spi.SqlAppender;
911
import org.hibernate.type.descriptor.jdbc.JdbcType;
1012
import org.hibernate.type.descriptor.jdbc.JsonArrayJdbcType;
@@ -27,6 +29,7 @@ public GaussDBCastingJsonArrayJdbcType(JdbcType elementJdbcType, boolean jsonb)
2729
@Override
2830
public void appendWriteExpression(
2931
String writeExpression,
32+
@Nullable Size size,
3033
SqlAppender appender,
3134
Dialect dialect) {
3235
appender.append( "cast(" );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBCastingJsonJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
*/
55
package org.hibernate.community.dialect;
66

7+
import org.checkerframework.checker.nullness.qual.Nullable;
78
import org.hibernate.dialect.Dialect;
9+
import org.hibernate.engine.jdbc.Size;
810
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
911
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
1012
import org.hibernate.sql.ast.spi.SqlAppender;
@@ -46,6 +48,7 @@ public AggregateJdbcType resolveAggregateJdbcType(
4648
@Override
4749
public void appendWriteExpression(
4850
String writeExpression,
51+
@Nullable Size size,
4952
SqlAppender appender,
5053
Dialect dialect) {
5154
appender.append( "cast(" );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/GaussDBStructuredJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import java.sql.PreparedStatement;
99
import java.sql.SQLException;
1010

11+
import org.checkerframework.checker.nullness.qual.Nullable;
1112
import org.hibernate.boot.model.naming.Identifier;
1213
import org.hibernate.dialect.Dialect;
1314
import org.hibernate.dialect.type.AbstractPostgreSQLStructJdbcType;
15+
import org.hibernate.engine.jdbc.Size;
1416
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
1517
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
1618
import org.hibernate.sql.ast.spi.SqlAppender;
@@ -59,6 +61,7 @@ public AggregateJdbcType resolveAggregateJdbcType(
5961
@Override
6062
public void appendWriteExpression(
6163
String writeExpression,
64+
@Nullable Size size,
6265
SqlAppender appender,
6366
Dialect dialect) {
6467
appender.append( "cast(" );

hibernate-core/src/main/java/org/hibernate/dialect/function/CastFunction.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
import java.util.List;
99

1010
import org.hibernate.dialect.Dialect;
11+
import org.hibernate.engine.jdbc.Size;
1112
import org.hibernate.engine.spi.SessionFactoryImplementor;
1213
import org.hibernate.metamodel.mapping.JdbcMapping;
14+
import org.hibernate.metamodel.mapping.SqlTypedMapping;
1315
import org.hibernate.metamodel.model.domain.ReturnableType;
1416
import org.hibernate.query.sqm.CastType;
1517
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
@@ -77,9 +79,15 @@ public void render(
7779
renderCastArrayToString( sqlAppender, arguments.get( 0 ), dialect, walker );
7880
}
7981
else {
80-
String castPattern = targetJdbcMapping.getJdbcType().castFromPattern( sourceMapping );
82+
final Size targetSize = targetJdbcMapping instanceof SqlTypedMapping sqlTypedMapping
83+
? sqlTypedMapping.toSize()
84+
: null;
85+
String castPattern = targetJdbcMapping.getJdbcType().castFromPattern( sourceMapping, targetSize );
8186
if ( castPattern == null ) {
82-
castPattern = sourceMapping.getJdbcType().castToPattern( targetJdbcMapping );
87+
final Size sourceSize = sourceMapping instanceof SqlTypedMapping sqlTypedMapping
88+
? sqlTypedMapping.toSize()
89+
: null;
90+
castPattern = sourceMapping.getJdbcType().castToPattern( targetJdbcMapping, sourceSize );
8391
if ( castPattern == null ) {
8492
castPattern = dialect.castPattern( sourceType, targetType );
8593
}

hibernate-core/src/main/java/org/hibernate/dialect/type/MariaDBCastingJsonArrayJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
*/
55
package org.hibernate.dialect.type;
66

7+
import org.checkerframework.checker.nullness.qual.Nullable;
78
import org.hibernate.dialect.Dialect;
9+
import org.hibernate.engine.jdbc.Size;
810
import org.hibernate.sql.ast.spi.SqlAppender;
911
import org.hibernate.type.descriptor.jdbc.JdbcType;
1012
import org.hibernate.type.descriptor.jdbc.JsonArrayJdbcType;
@@ -21,6 +23,7 @@ public MariaDBCastingJsonArrayJdbcType(JdbcType elementJdbcType) {
2123
@Override
2224
public void appendWriteExpression(
2325
String writeExpression,
26+
@Nullable Size size,
2427
SqlAppender appender,
2528
Dialect dialect) {
2629
appender.append( "json_extract(" );

hibernate-core/src/main/java/org/hibernate/dialect/type/MariaDBCastingJsonJdbcType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
*/
55
package org.hibernate.dialect.type;
66

7+
import org.checkerframework.checker.nullness.qual.Nullable;
78
import org.hibernate.dialect.Dialect;
9+
import org.hibernate.engine.jdbc.Size;
810
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
911
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
1012
import org.hibernate.sql.ast.spi.SqlAppender;
@@ -35,6 +37,7 @@ public AggregateJdbcType resolveAggregateJdbcType(
3537
@Override
3638
public void appendWriteExpression(
3739
String writeExpression,
40+
@Nullable Size size,
3841
SqlAppender appender,
3942
Dialect dialect) {
4043
appender.append( "json_extract(" );

0 commit comments

Comments
 (0)