Skip to content

Commit 1bbd111

Browse files
HNSW index: add nearest neighbor query condition
1 parent a9d24f5 commit 1bbd111

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

objectbox-java/src/main/java/io/objectbox/Property.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2019 ObjectBox Ltd. All rights reserved.
2+
* Copyright 2017-2024 ObjectBox Ltd. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222

2323
import javax.annotation.Nullable;
2424

25+
import io.objectbox.annotation.HnswIndex;
2526
import io.objectbox.annotation.apihint.Internal;
2627
import io.objectbox.converter.PropertyConverter;
2728
import io.objectbox.exception.DbException;
@@ -33,6 +34,7 @@
3334
import io.objectbox.query.PropertyQueryConditionImpl.LongArrayCondition;
3435
import io.objectbox.query.PropertyQueryConditionImpl.LongCondition;
3536
import io.objectbox.query.PropertyQueryConditionImpl.LongLongCondition;
37+
import io.objectbox.query.PropertyQueryConditionImpl.NearestNeighborCondition;
3638
import io.objectbox.query.PropertyQueryConditionImpl.NullCondition;
3739
import io.objectbox.query.PropertyQueryConditionImpl.StringArrayCondition;
3840
import io.objectbox.query.PropertyQueryConditionImpl.StringCondition;
@@ -302,6 +304,22 @@ public PropertyQueryCondition<ENTITY> between(double lowerBoundary, double upper
302304
lowerBoundary, upperBoundary);
303305
}
304306

307+
/**
308+
* Performs an approximate nearest neighbor (ANN) search to find objects near to the given {@code queryVector}.
309+
* <p>
310+
* This requires the vector property to have an {@link HnswIndex}.
311+
* <p>
312+
* The dimensions of the query vector should be at least the dimensions of this vector property.
313+
* <p>
314+
* Use {@code maxResultCount} to set the maximum number of objects to return by the ANN condition. Hint: it can also
315+
* be used as the "ef" HNSW parameter to increase the search quality in combination with a query limit. For example,
316+
* use maxResultCount of 100 with a Query limit of 10 to have 10 results that are of potentially better quality than
317+
* just passing in 10 for maxResultCount (quality/performance tradeoff).
318+
*/
319+
public PropertyQueryCondition<ENTITY> nearestNeighborsF32(float[] queryVector, int maxResultCount) {
320+
return new NearestNeighborCondition<>(this, queryVector, maxResultCount);
321+
}
322+
305323
/** Creates an "equal ('=')" condition for this property. */
306324
public PropertyQueryCondition<ENTITY> equal(Date value) {
307325
return new LongCondition<>(this, LongCondition.Operation.EQUAL, value);

objectbox-java/src/main/java/io/objectbox/query/PropertyQueryConditionImpl.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2021 ObjectBox Ltd. All rights reserved.
2+
* Copyright 2020-2024 ObjectBox Ltd. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -458,4 +458,24 @@ void applyCondition(QueryBuilder<T> builder) {
458458
}
459459
}
460460
}
461+
462+
/**
463+
* Conditions for properties with an {@link io.objectbox.annotation.HnswIndex}.
464+
*/
465+
public static class NearestNeighborCondition<T> extends PropertyQueryConditionImpl<T> {
466+
467+
private final float[] queryVector;
468+
private final int maxResultCount;
469+
470+
public NearestNeighborCondition(Property<T> property, float[] queryVector, int maxResultCount) {
471+
super(property);
472+
this.queryVector = queryVector;
473+
this.maxResultCount = maxResultCount;
474+
}
475+
476+
@Override
477+
void applyCondition(QueryBuilder<T> builder) {
478+
builder.nearestNeighborsF32(property, queryVector, maxResultCount);
479+
}
480+
}
461481
}

objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2018 ObjectBox Ltd. All rights reserved.
2+
* Copyright 2017-2024 ObjectBox Ltd. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -206,6 +206,8 @@ private native long nativeRelationCount(long handle, long storeHandle, int relat
206206

207207
private native long nativeBetween(long handle, int propertyId, double value1, double value2);
208208

209+
private native long nativeNearestNeighborsF32(long handle, int propertyId, float[] queryVector, int maxResultCount);
210+
209211
// ------------------------------ Bytes ------------------------------
210212

211213
private native long nativeEqual(long handle, int propertyId, byte[] value);
@@ -896,6 +898,12 @@ public QueryBuilder<T> between(Property<T> property, double value1, double value
896898
return this;
897899
}
898900

901+
QueryBuilder<T> nearestNeighborsF32(Property<T> property, float[] queryVector, int maxResultCount) {
902+
verifyHandle();
903+
checkCombineCondition(nativeNearestNeighborsF32(handle, property.getId(), queryVector, maxResultCount));
904+
return this;
905+
}
906+
899907
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
900908
// Bytes
901909
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)