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 all 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
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 @@ -22,8 +22,10 @@
import java.util.function.Predicate;

import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
* The {@link AggregationPipeline} holds the collection of {@link AggregationOperation aggregation stages}.
Expand Down Expand Up @@ -82,6 +84,14 @@ public List<AggregationOperation> getOperations() {
return Collections.unmodifiableList(pipeline);
}

public @Nullable AggregationOperation firstOperation() {
return CollectionUtils.firstElement(pipeline);
}

public @Nullable AggregationOperation lastOperation() {
return CollectionUtils.lastElement(pipeline);
}

List<Document> toDocuments(AggregationOperationContext context) {

verify();
Expand All @@ -97,8 +107,8 @@ public boolean isOutOrMerge() {
return false;
}

AggregationOperation operation = pipeline.get(pipeline.size() - 1);
return isOut(operation) || isMerge(operation);
AggregationOperation operation = lastOperation();
return operation != null && (isOut(operation) || isMerge(operation));
}

void verify() {
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 @@ -356,6 +356,7 @@ public SortArray sort(Sort sort) {
* @return new instance of {@link SortArray}.
* @since 4.5
*/
@SuppressWarnings("NullAway")
public SortArray sort(Direction direction) {

if (usesFieldRef()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,10 @@ public Document toDocument(AggregationOperationContext context) {
}

$vectorSearch.append("index", indexName);
$vectorSearch.append("limit", limit.max());

if(limit.isLimited()) { // TODO: exception or pass it on?
$vectorSearch.append("limit", limit.max());
}

if (numCandidates != null) {
$vectorSearch.append("numCandidates", numCandidates);
Expand Down
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* 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;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.data.mongodb.core.aggregation.VectorSearchOperation;

/**
* Annotation to declare Vector Search queries directly on repository methods. Vector Search queries are used to search
* for similar documents based on vector embeddings typically returning
* {@link org.springframework.data.domain.SearchResults} and limited by either a
* {@link org.springframework.data.domain.Score} (within) or a {@link org.springframework.data.domain.Range} of scores
* (between).
* <p>
* Vector search must define an index name using the {@link #indexName()} attribute. The index must be created in the
* MongoDB Atlas cluster before executing the query. Any misspelling of the index name will result in returning no
* results.
* <p>
* When using pre-filters, you can either define {@link #filter()} or use query derivation to define the pre-filter.
* {@link org.springframework.data.domain.Vector} and distance parameters are considered once these are present. Vector
* search supports sorting and will consider {@link org.springframework.data.domain.Sort} parameters.
*
* @author Mark Paluch
* @since 5.0
* @see org.springframework.data.domain.Score
* @see org.springframework.data.domain.Vector
* @see org.springframework.data.domain.SearchResults
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Documented
@Query
@Hint
public @interface VectorSearch {

/**
* Configuration whether to use
* {@link org.springframework.data.mongodb.core.aggregation.VectorSearchOperation.SearchType#ANN} or
* {@link org.springframework.data.mongodb.core.aggregation.VectorSearchOperation.SearchType#ENN} for the search.
*
* @return the search type to use.
*/
VectorSearchOperation.SearchType searchType() default VectorSearchOperation.SearchType.DEFAULT;

/**
* Name of the Atlas Vector Search index to use. Atlas Vector Search doesn't return results if you misspell the index
* name or if the specified index doesn't already exist on the cluster.
*
* @return name of the Atlas Vector Search index to use.
*/
@AliasFor(annotation = Hint.class, value = "indexName")
String indexName();

/**
* Indexed vector type field to search. This is defaulted from the domain model using the first Vector property found.
*
* @return an empty String by default.
*/
String path() default "";

/**
* Takes a MongoDB JSON (MQL) string defining the pre-filter against indexed fields. Supports Value Expressions. Alias
* for {@link VectorSearch#filter}.
*
* @return an empty String by default.
*/
@AliasFor(annotation = Query.class)
String value() default "";

/**
* Takes a MongoDB JSON (MQL) string defining the pre-filter against indexed fields. Supports Value Expressions. Alias
* for {@link VectorSearch#value}.
*
* @return an empty String by default.
*/
@AliasFor(annotation = Query.class, value = "value")
String filter() default "";

/**
* Number of documents to return in the results. This value can't exceed the value of {@link #numCandidates} if you
* specify {@link #numCandidates}. Limit accepts Value Expressions. A Vector Search method cannot define both,
* {@code limit()} and a {@link org.springframework.data.domain.Limit} parameter. Supports Value Expressions.
*
* @return number of documents to return in the results.
*/
String limit() default "";

/**
* Number of nearest neighbors to use during the search. Value must be less than or equal to ({@code <=})
* {@code 10000}. You can't specify a number less than the {@link #limit() number of documents to return}. We
* recommend that you specify a number at least {@code 20} times higher than the {@link #limit() number of documents
* to return} to increase accuracy.
* <p>
* This over-request pattern is the recommended way to trade off latency and recall in your ANN searches, and we
* recommend tuning this parameter based on your specific dataset size and query requirements. Required if the query
* uses
* {@link org.springframework.data.mongodb.core.aggregation.VectorSearchOperation.SearchType#ANN}/{@link org.springframework.data.mongodb.core.aggregation.VectorSearchOperation.SearchType#DEFAULT}.
* Supports Value Expressions.
*
* @return number of nearest neighbors to use during the search.
*/
String numCandidates() default "";

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Score;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Vector;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
Expand Down Expand Up @@ -129,6 +131,21 @@ public Range<Distance> getDistanceRange() {
return null;
}

@Override
public @Nullable Vector getVector() {
return null;
}

@Override
public @Nullable Score getScore() {
return null;
}

@Override
public @Nullable Range<Score> getScoreRange() {
return null;
}

@Override
public @Nullable Point getGeoNearLocation() {
return null;
Expand Down
Loading