Skip to content

CSHARP-4768: Introduce $vectorSearch aggregation stage#1187

Merged
BorisDog merged 1 commit into
mongodb:masterfrom
BorisDog:csharp4768
Oct 6, 2023
Merged

CSHARP-4768: Introduce $vectorSearch aggregation stage#1187
BorisDog merged 1 commit into
mongodb:masterfrom
BorisDog:csharp4768

Conversation

@BorisDog

Copy link
Copy Markdown
Contributor

No description provided.

@BorisDog BorisDog requested a review from a team as a code owner September 29, 2023 00:46
@BorisDog BorisDog requested review from JamesKovacs and adelinowona and removed request for a team September 29, 2023 00:46

@adelinowona adelinowona left a comment

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.

LGTM + minor comments

operatorName,
(s, sr, linqProvider) =>
{
var vectorSearchOperator = new BsonDocument()

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.

Redundant () after BsonDocument.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

}

[Fact]
public void VectorSearch_should_add_expected_stage_with_floats_vector()

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.

This test and VectorSearch_should_add_expected_stage seem to be exact except for the queryVector used. Maybe combine them into one method and use parameters for the different queryVectors?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Discussing offline.

/// Creates a $vectorSearch stage.
/// </summary>
/// <typeparam name="TInput">The type of the input documents.</typeparam>
/// <returns>The stage.</returns>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Xml docs for parameters are missed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, fixed.

public static PipelineStageDefinition<TInput, TInput> VectorSearch<TInput>(
FieldDefinition<TInput> field,
VectorSearchQueryVector queryVector,
int limit,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we validate limit parameter's value?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, done.


for (int i = 0; i < value.Count; i++)
{
bsonWriter.WriteDouble(span[i].ToDouble(null));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we use QueryVectorBsonArray<T>.Values property here instead to localize all convertion logic there?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Could be a good idea, but we want to skip allocation for BsonDouble in .Values (it's implicit allocation)

Comment thread tests/MongoDB.Driver.Tests/VectorSearchQueryVectorTests.cs Outdated

@sanych-sun sanych-sun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@adelinowona adelinowona left a comment

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.

LGTM

@JamesKovacs JamesKovacs left a comment

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.

Minor feedback. Plus consider Robert's idea of supporting casts from IEnumerable<T> to QueryVector.

/// <returns>The stage.</returns>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <returns>The stage.</returns>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <returns>The stage.</returns>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <returns>The stage.</returns>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <returns>The stage.</returns>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <param name="options">The options.</param>
/// <returns>
/// The fluent aggregate interface.
/// A new pipeline with an additional stage.

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.

Formatting. Most others have it on a single line.

/// <param name="options">The options.</param>
/// <returns>
/// The fluent aggregate interface.
/// A new pipeline with an additional stage.

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.

Formatting. Most others have it on a single line.

/// <param name="options">The vector search options.</param>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <param name="options">The vector search options.</param>
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>

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.

Formatting. Most others have it on a single line.

/// <summary>
/// Vector search query vector.
/// </summary>
public sealed class VectorSearchQueryVector

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.

VectorSearchQueryVector reads like Vector---Vector to me. Having Vector at both ends of the class name sounds strange to my ear. Is there any ambiguity - either in our API or in C# - if we call it QueryVector?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, changed to QueryVector.

@BorisDog BorisDog requested a review from JamesKovacs October 5, 2023 01:10

@JamesKovacs JamesKovacs left a comment

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.

LGTM

Comment thread src/MongoDB.Driver/QueryVector.cs
Comment thread src/MongoDB.Driver/QueryVector.cs
Comment thread src/MongoDB.Driver/QueryVector.cs
Comment thread src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs
/// <returns>
/// A new pipeline with an additional stage.
/// </returns>
/// <returns>A new pipeline with an additional stage.</returns>

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.

This is a lot of diffs unrelated to this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, just used the opportunity of modifying this file to fix comments.

Comment thread src/MongoDB.Driver/QueryVector.cs
Comment thread src/MongoDB.Driver/QueryVector.cs Outdated
/// <summary>
/// Gets the underlying BSON array.
/// </summary>
internal BsonArray Array { get; }

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.

Add warning comment so we don't make this public by mistake some day:

internal BsonArray Array { get; } // do not make public because in the case of ReadOnlyMemory the BsonArray subclass is not fully functional

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

/// </returns>
public static implicit operator QueryVector(ReadOnlyMemory<int> readOnlyMemory) => new(readOnlyMemory);
}

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.

Add a warning comment that this subclass of BsonArray is not fully functional and is only intended to be serialized:

// WARNING: this class is a very partial implementation of a BsonArray subclass
// it is not fully functional and is only intended to be serialized

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

_memory = memory;
}

public override int Count => _memory.Length;

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 think you can remove this property (but see suggested change below).

public override int Count => _memory.Length;

public ReadOnlySpan<T> Span => _memory.Span;

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.

Add a comment explaining that this property ONLY exists for testing.

// note: Values is only used in tests

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.

Perhaps if the tests were written differently this property wouldn't be needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Left the Values and Count properties for simplicity, and added a comment.

Comment thread src/MongoDB.Driver/QueryVector.cs Outdated
{
get
{
for (int i = 0; i < _memory.Length; i++)

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.

for (int i = 0; i < span.Length; i++)

Since the index is being used with Span[i] I would rather control the for loop with span.Length (I realize of course that both evaluate to the same number, but I'd rather not have a level of indirection).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point, done.

@BorisDog BorisDog requested a review from rstam October 5, 2023 23:25

@rstam rstam left a comment

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.

LGTM

Thanks for walking through the justifications for ReadOnlyMemory in the public API with me. I wish I had known sooner that we were talking about vectors of 2000 numbers instead of less than 10.

@BorisDog BorisDog merged commit f7e5a31 into mongodb:master Oct 6, 2023
@BorisDog BorisDog deleted the csharp4768 branch October 6, 2023 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants