Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.mongodb.client.model;

import com.mongodb.lang.Nullable;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.codecs.configuration.CodecRegistry;
Expand All @@ -38,10 +39,32 @@
*/
public final class VectorSearchIndexDefinition implements SearchIndexDefinition {
private final List<? extends Bson> fields;
@Nullable
private final Bson storedSource;

VectorSearchIndexDefinition(final List<? extends Bson> fields) {
this(fields, null);
}

VectorSearchIndexDefinition(final List<? extends Bson> fields, @Nullable final Bson storedSource) {
doesNotContainNull("fields", notNull("fields", fields));
this.fields = new ArrayList<>(fields);
this.storedSource = storedSource;
}

/**
* Creates a new {@link VectorSearchIndexDefinition} with the specified stored source configuration.
*
* <p>The stored source configuration controls which fields are stored in the index
* and can be returned without reading the full document from the collection.</p>
*
* @param storedSource a document specifying the stored source configuration,
* e.g., {@code {"include": ["field1", "field2"]}} or {@code {"exclude": ["field3"]}}
* @return a new {@link VectorSearchIndexDefinition} with the stored source configuration
* @since 5.8
*/
public VectorSearchIndexDefinition storedSource(final Bson storedSource) {
return new VectorSearchIndexDefinition(this.fields, notNull("storedSource", storedSource));
}

@Override
Expand All @@ -50,13 +73,18 @@ public <TDocument> BsonDocument toBsonDocument(final Class<TDocument> documentCl
for (Bson field : fields) {
fieldArray.add(field.toBsonDocument(documentClass, codecRegistry));
}
return new BsonDocument("fields", fieldArray);
BsonDocument document = new BsonDocument("fields", fieldArray);
if (storedSource != null) {
document.append("storedSource", storedSource.toBsonDocument(documentClass, codecRegistry));
}
return document;
}

@Override
public String toString() {
return "VectorSearchIndexDefinition{"
+ "fields=" + fields
+ ", storedSource=" + storedSource
+ '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.mongodb.annotations.Immutable;
import com.mongodb.internal.client.model.AbstractConstructibleBson;
import org.bson.BsonBoolean;
import org.bson.BsonDocument;
import org.bson.Document;
import org.bson.conversions.Bson;
Expand Down Expand Up @@ -45,7 +46,12 @@ protected VectorSearchConstructibleBson newSelf(final Bson base, final Document

@Override
public VectorSearchOptions filter(final Bson filter) {
return newAppended("filter", notNull("name", filter));
return newAppended("filter", notNull("filter", filter));
}

@Override
public VectorSearchOptions returnStoredSource(final boolean returnStoredSource) {
return newAppended("returnStoredSource", new BsonBoolean(returnStoredSource));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ public interface VectorSearchOptions extends Bson {
*/
VectorSearchOptions filter(Bson filter);

/**
* Creates a new {@link VectorSearchOptions} that instructs to return only stored source fields.
*
* @param returnStoredSource The option to return only stored source fields.
* @return A new {@link VectorSearchOptions}.
* @mongodb.atlas.manual atlas-vector-search/vector-search-stage/ $vectorSearch
* @since 5.8
*/
VectorSearchOptions returnStoredSource(boolean returnStoredSource);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

do you think it's better to make it
returnStoredSourceOnly() not sure what is better
by default it's false which according to documentation is

implicit full document lookup on the backend database
so I believe users will only use this builder method to only set it to true


/**
* Creates a new {@link VectorSearchOptions} with the specified option in situations when there is no builder method
* that better satisfies your needs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,36 @@ void vectorSearchRejectsEmptyVarargs() {
void vectorSearchRejectsEmptyList() {
assertThrows(IllegalArgumentException.class, () -> SearchIndexDefinition.vectorSearch(emptyList()));
}

@Test
void vectorSearchWithStoredSource() {
VectorSearchIndexDefinition definition = SearchIndexDefinition.vectorSearch(
vectorField("embedding")
.numDimensions(1536)
.similarity("cosine")
).storedSource(new Document("include", asList("plot", "title")));

assertEquals(
new BsonDocument("fields", new BsonArray(asList(
new BsonDocument("type", new BsonString("vector"))
.append("path", new BsonString("embedding"))
.append("numDimensions", new BsonInt32(1536))
.append("similarity", new BsonString("cosine"))
))).append("storedSource", new BsonDocument("include", new BsonArray(asList(
new BsonString("plot"),
new BsonString("title")
)))),
definition.toBsonDocument()
);
}

@Test
void vectorSearchStoredSourceRejectsNull() {
VectorSearchIndexDefinition definition = SearchIndexDefinition.vectorSearch(
vectorField("embedding")
.numDimensions(1536)
.similarity("cosine")
);
assertThrows(IllegalArgumentException.class, () -> definition.storedSource(null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,30 @@ void optionsExact() {
);
}

@Test
void returnStoredSourceApproximate() {
assertEquals(
new BsonDocument()
.append("returnStoredSource", new BsonBoolean(true))
.append("numCandidates", new BsonInt64(1)),
VectorSearchOptions.approximateVectorSearchOptions(1)
.returnStoredSource(true)
.toBsonDocument()
);
}

@Test
void returnStoredSourceExact() {
assertEquals(
new BsonDocument()
.append("returnStoredSource", new BsonBoolean(true))
.append("exact", new BsonBoolean(true)),
VectorSearchOptions.exactVectorSearchOptions()
.returnStoredSource(true)
.toBsonDocument()
);
}

@Test
void approximateVectorSearchOptionsIsUnmodifiable() {
String expected = VectorSearchOptions.approximateVectorSearchOptions(1).toBsonDocument().toJson();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ class SearchIndexDefinitionSpec extends BaseSpec {
)
}

it should "create a vectorSearch definition with storedSource" in {
toBson(
vectorSearch(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am just curios , why do we also add scala tests when it uses existing java classes that we already unit tested ?

vectorField("embedding").numDimensions(1536).similarity("cosine")
).storedSource(Document("include" -> List("plot", "title")))
) should equal(
Document(
"""{"fields": [
|{"type": "vector", "path": "embedding", "numDimensions": 1536, "similarity": "cosine"}
|], "storedSource": {"include": ["plot", "title"]}}""".stripMargin.replaceAll("\n", " ")
)
)
}

it should "create a SearchIndexModel with VectorSearchIndexDefinition" in {
val definition = vectorSearch(
vectorField("embedding").numDimensions(1536).similarity("cosine")
Expand Down