Skip to content

Commit 3227eed

Browse files
authored
feat(vector): Introduce support for Neo4j Vector (#1663)
This update introduces support for Neo4j Vector types together with Bolt 6.0. The diagram below illustrates the new types. ```mermaid classDiagram class Vector { +elementType() Class<?> +length() int } class ByteVector { +toArray() byte[] } class ShortVector { +toArray() short[] } class IntVector { +toArray() int[] } class LongVector { +toArray() long[] } class FloatVector { +toArray() float[] } class DoubleVector { +toArray() double[] } Vector <|-- ByteVector Vector <|-- ShortVector Vector <|-- IntVector Vector <|-- LongVector Vector <|-- FloatVector Vector <|-- DoubleVector ```
1 parent a2ed497 commit 3227eed

34 files changed

+1284
-10
lines changed

driver/clirr-ignored-differences.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,4 +818,10 @@
818818
<method>org.neo4j.driver.Logging systemLogging()</method>
819819
</difference>
820820

821+
<difference>
822+
<className>org/neo4j/driver/types/TypeSystem</className>
823+
<differenceType>7012</differenceType>
824+
<method>org.neo4j.driver.types.Type VECTOR()</method>
825+
</difference>
826+
821827
</differences>

driver/src/main/java/org/neo4j/driver/Values.java

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,15 @@
4242
import org.neo4j.driver.exceptions.ClientException;
4343
import org.neo4j.driver.internal.AsValue;
4444
import org.neo4j.driver.internal.GqlStatusError;
45+
import org.neo4j.driver.internal.InternalByteVector;
46+
import org.neo4j.driver.internal.InternalDoubleVector;
47+
import org.neo4j.driver.internal.InternalFloatVector;
48+
import org.neo4j.driver.internal.InternalIntVector;
4549
import org.neo4j.driver.internal.InternalIsoDuration;
50+
import org.neo4j.driver.internal.InternalLongVector;
4651
import org.neo4j.driver.internal.InternalPoint2D;
4752
import org.neo4j.driver.internal.InternalPoint3D;
53+
import org.neo4j.driver.internal.InternalShortVector;
4854
import org.neo4j.driver.internal.value.BooleanValue;
4955
import org.neo4j.driver.internal.value.BytesValue;
5056
import org.neo4j.driver.internal.value.DateTimeValue;
@@ -60,6 +66,7 @@
6066
import org.neo4j.driver.internal.value.PointValue;
6167
import org.neo4j.driver.internal.value.StringValue;
6268
import org.neo4j.driver.internal.value.TimeValue;
69+
import org.neo4j.driver.internal.value.VectorValue;
6370
import org.neo4j.driver.mapping.Property;
6471
import org.neo4j.driver.types.Entity;
6572
import org.neo4j.driver.types.IsoDuration;
@@ -69,6 +76,7 @@
6976
import org.neo4j.driver.types.Point;
7077
import org.neo4j.driver.types.Relationship;
7178
import org.neo4j.driver.types.TypeSystem;
79+
import org.neo4j.driver.types.Vector;
7280
import org.neo4j.driver.util.Preview;
7381

7482
/**
@@ -170,6 +178,9 @@ public static Value value(Object value) {
170178
if (value instanceof Point) {
171179
return value((Point) value);
172180
}
181+
if (value instanceof Vector vector) {
182+
return value(vector);
183+
}
173184

174185
if (value instanceof List<?>) {
175186
return value((List<Object>) value);
@@ -469,10 +480,11 @@ public static Value value(java.lang.Record record) {
469480
for (var recordComponent : recordComponents) {
470481
var propertyAnnotation = recordComponent.getAnnotation(Property.class);
471482
var property = propertyAnnotation != null ? propertyAnnotation.value() : recordComponent.getName();
483+
var isVector = recordComponent.getAnnotation(org.neo4j.driver.mapping.Vector.class) != null;
472484
Value value;
473485
try {
474486
var objectValue = recordComponent.getAccessor().invoke(record);
475-
value = (objectValue != null) ? value(objectValue) : null;
487+
value = (objectValue != null) ? isVector ? vector(objectValue) : value(objectValue) : null;
476488
} catch (Throwable throwable) {
477489
var message = "Failed to map '%s' property to value during mapping '%s' to map value"
478490
.formatted(property, record.getClass().getCanonicalName());
@@ -996,4 +1008,99 @@ public static Function<Value, List<Object>> ofList() {
9961008
public static <T> Function<Value, List<T>> ofList(final Function<Value, T> innerMap) {
9971009
return value -> value.asList(innerMap);
9981010
}
1011+
1012+
/**
1013+
* Returns Neo4j Vector that holds a sequence of {@code byte} values.
1014+
*
1015+
* @param elements the vector elements
1016+
* @return the vector value
1017+
* @since 6.0.0
1018+
*/
1019+
@Preview(name = "Neo4j Vector")
1020+
public static Value vector(byte[] elements) {
1021+
return value(new InternalByteVector(elements));
1022+
}
1023+
1024+
/**
1025+
* Returns Neo4j Vector that holds a sequence of {@code short} values.
1026+
*
1027+
* @param elements the vector elements
1028+
* @return the vector value
1029+
* @since 6.0.0
1030+
*/
1031+
@Preview(name = "Neo4j Vector")
1032+
public static Value vector(short[] elements) {
1033+
return value(new InternalShortVector(elements));
1034+
}
1035+
1036+
/**
1037+
* Returns Neo4j Vector that holds a sequence of {@code int} values.
1038+
*
1039+
* @param elements the vector elements
1040+
* @return the vector value
1041+
* @since 6.0.0
1042+
*/
1043+
@Preview(name = "Neo4j Vector")
1044+
public static Value vector(int[] elements) {
1045+
return value(new InternalIntVector(elements));
1046+
}
1047+
1048+
/**
1049+
* Returns Neo4j Vector that holds a sequence of {@code long} values.
1050+
*
1051+
* @param elements the vector elements
1052+
* @return the vector value
1053+
* @since 6.0.0
1054+
*/
1055+
@Preview(name = "Neo4j Vector")
1056+
public static Value vector(long[] elements) {
1057+
return value(new InternalLongVector(elements));
1058+
}
1059+
1060+
/**
1061+
* Returns Neo4j Vector that holds a sequence of {@code float} values.
1062+
*
1063+
* @param elements the vector elements
1064+
* @return the vector value
1065+
* @since 6.0.0
1066+
*/
1067+
@Preview(name = "Neo4j Vector")
1068+
public static Value vector(float[] elements) {
1069+
return value(new InternalFloatVector(elements));
1070+
}
1071+
1072+
/**
1073+
* Returns Neo4j Vector that holds a sequence of {@code double} values.
1074+
*
1075+
* @param elements the vector elements
1076+
* @return the vector value
1077+
* @since 6.0.0
1078+
*/
1079+
@Preview(name = "Neo4j Vector")
1080+
public static Value vector(double[] elements) {
1081+
return value(new InternalDoubleVector(elements));
1082+
}
1083+
1084+
private static Value value(Vector vector) {
1085+
return new VectorValue(vector);
1086+
}
1087+
1088+
private static Value vector(Object array) {
1089+
if (array instanceof byte[] elements) {
1090+
return value(Values.vector(elements));
1091+
} else if (array instanceof short[] elements) {
1092+
return value(Values.vector(elements));
1093+
} else if (array instanceof int[] elements) {
1094+
return value(Values.vector(elements));
1095+
} else if (array instanceof long[] elements) {
1096+
return value(Values.vector(elements));
1097+
} else if (array instanceof float[] elements) {
1098+
return value(Values.vector(elements));
1099+
} else if (array instanceof double[] elements) {
1100+
return value(Values.vector(elements));
1101+
} else {
1102+
throw new IllegalArgumentException(
1103+
"Unsupported vector element type: " + array.getClass().getName());
1104+
}
1105+
}
9991106
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import java.lang.reflect.Array;
20+
import java.util.Objects;
21+
import org.neo4j.bolt.connection.values.Vector;
22+
23+
public abstract class AbstractArrayVector<T> implements Vector {
24+
private final Class<?> elementType;
25+
private final int length;
26+
protected final T elements;
27+
28+
AbstractArrayVector(T elements) {
29+
this.elementType = elements.getClass().getComponentType();
30+
this.length = Array.getLength(elements);
31+
this.elements = arraycopy(elements);
32+
}
33+
34+
public Class<?> elementType() {
35+
return elementType;
36+
}
37+
38+
public int length() {
39+
return length;
40+
}
41+
42+
public T toArray() {
43+
return arraycopy(elements);
44+
}
45+
46+
@Override
47+
public Object elements() {
48+
return elements;
49+
}
50+
51+
@Override
52+
public boolean equals(Object o) {
53+
if (o == null || getClass() != o.getClass()) return false;
54+
var that = (AbstractArrayVector<?>) o;
55+
return length == that.length
56+
&& Objects.equals(elementType, that.elementType)
57+
&& Objects.equals(elements, that.elements);
58+
}
59+
60+
@Override
61+
public int hashCode() {
62+
return Objects.hash(elementType, length, elements);
63+
}
64+
65+
@Override
66+
public String toString() {
67+
return "AbstractArrayVector{" + "elementType="
68+
+ elementType + ", length="
69+
+ length + ", elements="
70+
+ elements + '}';
71+
}
72+
73+
@SuppressWarnings({"unchecked", "SuspiciousSystemArraycopy"})
74+
private T arraycopy(T elements) {
75+
var result = (T) Array.newInstance(elementType, length);
76+
System.arraycopy(elements, 0, result, 0, length);
77+
return result;
78+
}
79+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import org.neo4j.driver.types.ByteVector;
20+
21+
public final class InternalByteVector extends AbstractArrayVector<byte[]> implements ByteVector {
22+
public InternalByteVector(byte[] elements) {
23+
super(elements);
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import org.neo4j.driver.types.DoubleVector;
20+
21+
public final class InternalDoubleVector extends AbstractArrayVector<double[]> implements DoubleVector {
22+
public InternalDoubleVector(double[] elements) {
23+
super(elements);
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import org.neo4j.driver.types.FloatVector;
20+
21+
public final class InternalFloatVector extends AbstractArrayVector<float[]> implements FloatVector {
22+
public InternalFloatVector(float[] elements) {
23+
super(elements);
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import org.neo4j.driver.types.IntVector;
20+
21+
public final class InternalIntVector extends AbstractArrayVector<int[]> implements IntVector {
22+
public InternalIntVector(int[] elements) {
23+
super(elements);
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import org.neo4j.driver.types.LongVector;
20+
21+
public final class InternalLongVector extends AbstractArrayVector<long[]> implements LongVector {
22+
public InternalLongVector(long[] elements) {
23+
super(elements);
24+
}
25+
}

0 commit comments

Comments
 (0)