Skip to content

Explore Search Results #4960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>5.0.0-SNAPSHOT</version>
<version>5.0.0-SEARCH-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand All @@ -26,7 +26,7 @@
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>4.0.0-SNAPSHOT</springdata.commons>
<springdata.commons>4.0.0-SEARCH-RESULT-SNAPSHOT</springdata.commons>
<mongo>5.4.0</mongo>
<jmh.version>1.19</jmh.version>
</properties>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>5.0.0-SNAPSHOT</version>
<version>5.0.0-SEARCH-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>5.0.0-SNAPSHOT</version>
<version>5.0.0-SEARCH-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems to have ended up in the wrong directory. should have been src/test/java, right?

Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository.query;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.lang.reflect.Method;

import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import org.springframework.data.domain.Limit;
import org.springframework.data.domain.Score;
import org.springframework.data.domain.SearchResults;
import org.springframework.data.domain.Vector;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mongodb.core.aggregation.VectorSearchOperation;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.VectorSearch;
import org.springframework.data.mongodb.util.json.ParameterBindingContext;
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.AnnotationRepositoryMetadata;
import org.springframework.data.repository.query.ValueExpressionDelegate;

/**
* Unit tests for {@link VectorSearchDelegate}.
*
* @author Mark Paluch
*/
class VectorSearchDelegateUnitTests {

MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, new MongoMappingContext());

@Test
void shouldConsiderDerivedLimit() throws ReflectiveOperationException {

Method method = VectorSearchRepository.class.getMethod("searchTop10ByEmbeddingNear", Vector.class, Score.class);

MongoQueryMethod queryMethod = getMongoQueryMethod(method);
MongoParametersParameterAccessor accessor = getAccessor(queryMethod, Vector.of(1, 2), Score.of(1));

VectorSearchDelegate.QueryMetadata query = createQueryMetadata(queryMethod, accessor);

assertThat(query.query().getLimit()).isEqualTo(10);
assertThat(query.numCandidates()).isEqualTo(10 * 20);
}

@Test
void shouldNotSetNumCandidates() throws ReflectiveOperationException {

Method method = VectorSearchRepository.class.getMethod("searchTop10EnnByEmbeddingNear", Vector.class, Score.class);

MongoQueryMethod queryMethod = getMongoQueryMethod(method);
MongoParametersParameterAccessor accessor = getAccessor(queryMethod, Vector.of(1, 2), Score.of(1));

VectorSearchDelegate.QueryMetadata query = createQueryMetadata(queryMethod, accessor);

assertThat(query.query().getLimit()).isEqualTo(10);
assertThat(query.numCandidates()).isNull();
}

@Test
void shouldConsiderProvidedLimit() throws ReflectiveOperationException {

Method method = VectorSearchRepository.class.getMethod("searchTop10ByEmbeddingNear", Vector.class, Score.class,
Limit.class);

MongoQueryMethod queryMethod = getMongoQueryMethod(method);
MongoParametersParameterAccessor accessor = getAccessor(queryMethod, Vector.of(1, 2), Score.of(1), Limit.of(11));

VectorSearchDelegate.QueryMetadata query = createQueryMetadata(queryMethod, accessor);

assertThat(query.query().getLimit()).isEqualTo(11);
assertThat(query.numCandidates()).isEqualTo(11 * 20);
}

private VectorSearchDelegate.QueryMetadata createQueryMetadata(MongoQueryMethod queryMethod,
MongoParametersParameterAccessor accessor) {

VectorSearchDelegate delegate = new VectorSearchDelegate(queryMethod, converter, ValueExpressionDelegate.create());

return delegate.createQuery(mock(ValueExpressionEvaluator.class), queryMethod.getResultProcessor(), accessor,
Object.class, new ParameterBindingDocumentCodec(), mock(ParameterBindingContext.class));
}

private MongoQueryMethod getMongoQueryMethod(Method method) {
RepositoryMetadata metadata = AnnotationRepositoryMetadata.getMetadata(method.getDeclaringClass());
return new MongoQueryMethod(method, metadata, new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
}

@NotNull
private static MongoParametersParameterAccessor getAccessor(MongoQueryMethod queryMethod, Object... values) {
return new MongoParametersParameterAccessor(queryMethod, values);
}

interface VectorSearchRepository extends Repository<WithVector, String> {

@VectorSearch(indexName = "cos-index", searchType = VectorSearchOperation.SearchType.ANN)
SearchResults<WithVector> searchTop10ByEmbeddingNear(Vector vector, Score similarity);

@VectorSearch(indexName = "cos-index", searchType = VectorSearchOperation.SearchType.ENN)
SearchResults<WithVector> searchTop10EnnByEmbeddingNear(Vector vector, Score similarity);

@VectorSearch(indexName = "cos-index", searchType = VectorSearchOperation.SearchType.ANN)
SearchResults<WithVector> searchTop10ByEmbeddingNear(Vector vector, Score similarity, Limit limit);

}

static class WithVector {

Vector embedding;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ public <T> GeoResults<T> geoNear(NearQuery near, Class<?> domainType, String col
result.add(geoResult);
}

Distance avgDistance = new Distance(
Distance avgDistance = Distance.of(
result.size() == 0 ? 0 : aggregate.divide(new BigDecimal(result.size()), RoundingMode.HALF_UP).doubleValue(),
near.getMetric());

Expand Down Expand Up @@ -2654,7 +2654,9 @@ protected <S, T> List<T> doFind(String collectionName,

if (LOGGER.isDebugEnabled()) {

Document mappedSort = preparer instanceof SortingQueryCursorPreparer sqcp ? getMappedSortObject(sqcp.getSortObject(), entity) : null;
Document mappedSort = preparer instanceof SortingQueryCursorPreparer sqcp
? getMappedSortObject(sqcp.getSortObject(), entity)
: null;
LOGGER.debug(String.format("find using query: %s fields: %s sort: %s for class: %s in collection: %s",
serializeToJsonSafely(mappedQuery), mappedFields, serializeToJsonSafely(mappedSort), entityClass,
collectionName));
Expand Down Expand Up @@ -3553,7 +3555,7 @@ public GeoResult<T> doWith(Document object) {

T doWith = delegate.doWith(object);

return new GeoResult<>(doWith, new Distance(distance, metric));
return new GeoResult<>(doWith, Distance.of(distance, metric));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3227,7 +3227,7 @@ public Mono<GeoResult<T>> doWith(Document object) {

double distance = getDistance(object);

return delegate.doWith(object).map(doWith -> new GeoResult<>(doWith, new Distance(distance, metric)));
return delegate.doWith(object).map(doWith -> new GeoResult<>(doWith, Distance.of(distance, metric)));
}

double getDistance(Document object) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,5 @@ public Document getRawResults() {
Object object = rawResults.get("serverUsed");
return object instanceof String stringValue ? stringValue : null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ enum DocumentToCircleConverter implements Converter<Document, Circle> {
Assert.notNull(center, "Center must not be null");
Assert.notNull(radius, "Radius must not be null");

Distance distance = new Distance(toPrimitiveDoubleValue(radius));
Distance distance = Distance.of(toPrimitiveDoubleValue(radius));

if (source.containsKey("metric")) {

Expand Down Expand Up @@ -335,7 +335,7 @@ enum DocumentToSphereConverter implements Converter<Document, Sphere> {
Assert.notNull(center, "Center must not be null");
Assert.notNull(radius, "Radius must not be null");

Distance distance = new Distance(toPrimitiveDoubleValue(radius));
Distance distance = Distance.of(toPrimitiveDoubleValue(radius));

if (source.containsKey("metric")) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public Sphere(Point center, Distance radius) {
* @param radius
*/
public Sphere(Point center, double radius) {
this(center, new Distance(radius));
this(center, Distance.of(radius));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.bson.types.Decimal128;
import org.bson.types.ObjectId;
import org.bson.types.Symbol;

import org.springframework.data.mapping.model.SimpleTypeHolder;

import com.mongodb.DBRef;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.bson.Document;
import org.jspecify.annotations.Nullable;

import org.springframework.data.domain.Pageable;
import org.springframework.data.geo.CustomMetric;
import org.springframework.data.geo.Distance;
Expand Down Expand Up @@ -329,7 +330,7 @@ public NearQuery with(Pageable pageable) {
*/
@Contract("_ -> this")
public NearQuery maxDistance(double maxDistance) {
return maxDistance(new Distance(maxDistance, getMetric()));
return maxDistance(Distance.of(maxDistance, getMetric()));
}

/**
Expand All @@ -345,7 +346,7 @@ public NearQuery maxDistance(double maxDistance, Metric metric) {

Assert.notNull(metric, "Metric must not be null");

return maxDistance(new Distance(maxDistance, metric));
return maxDistance(Distance.of(maxDistance, metric));
}

/**
Expand Down Expand Up @@ -388,7 +389,7 @@ public NearQuery maxDistance(Distance distance) {
*/
@Contract("_ -> this")
public NearQuery minDistance(double minDistance) {
return minDistance(new Distance(minDistance, getMetric()));
return minDistance(Distance.of(minDistance, getMetric()));
}

/**
Expand All @@ -405,7 +406,7 @@ public NearQuery minDistance(double minDistance, Metric metric) {

Assert.notNull(metric, "Metric must not be null");

return minDistance(new Distance(minDistance, metric));
return minDistance(Distance.of(minDistance, metric));
}

/**
Expand Down Expand Up @@ -611,7 +612,7 @@ public NearQuery withReadPreference(ReadPreference readPreference) {
* Get the {@link ReadConcern} to use. Will return the underlying {@link #query(Query) queries}
* {@link Query#getReadConcern() ReadConcern} if present or the one defined on the {@link NearQuery#readConcern}
* itself.
*
*
* @return can be {@literal null} if none set.
* @since 4.1
* @see ReadConcernAware
Expand Down
Loading