Skip to content

.Net MEVD: Strongly-typed vector property selector - #10793

Closed
Adam Sitnik (adamsitnik) wants to merge 4 commits into
microsoft:feature-vector-data-preb1from
adamsitnik:vectorSearchSelector
Closed

Adam Sitnik (adamsitnik) wants to merge 4 commits into
microsoft:feature-vector-data-preb1from
adamsitnik:vectorSearchSelector

Conversation

@adamsitnik

@adamsitnik Adam Sitnik (adamsitnik) commented Mar 4, 2025 •

Copy link
Copy Markdown
Member

The property selector can return a property:

var results = await fixture.Collection.VectorizedSearchAsync(
    new ReadOnlyMemory<float>([1, 2, 3]),
    new() { VectorProperty = r => r.SomeVectorProp });

fixes #10420

@adamsitnik
Adam Sitnik (adamsitnik) requested a review from a team as a code owner March 4, 2025 20:22
@markwallace-microsoft Mark Wallace (markwallace-microsoft) added .NET Issue or Pull requests regarding .NET code kernel Issues or pull requests impacting the core kernel memory labels Mar 4, 2025
…o vectorSearchSelector

# Conflicts:
#	dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreRecordCollectionTests.cs
#	dotnet/src/Connectors/Connectors.Weaviate.UnitTests/WeaviateVectorStoreRecordCollectionQueryBuilderTests.cs
#	dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchVectorStoreRecordCollectionTests.cs
#	dotnet/src/VectorDataIntegrationTests/VectorDataIntegrationTests/Filter/BasicFilterTests.cs
@adamsitnik

Copy link
Copy Markdown
Member Author

Shay Rojansky (@roji) westey (@westey-m) Damn, it's late and it seems that one test is failing. I am going to fix it tomorrow and ask you for review again.

@adamsitnik
Adam Sitnik (adamsitnik) marked this pull request as draft March 4, 2025 21:02

@roji Shay Rojansky (roji) 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.

Thanks Adam Sitnik (@adamsitnik), looks great.

{
Verify.NotNull(vector);

if (this._propertyReader.FirstVectorPropertyName is null)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've removed this and similar guards from other types as the methods exposed by PropertyReader will simply throw in such cases.

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.

Yeah, I have similar changes in my Hybrid search PR as well, so we'll have to do some merging

@roji Shay Rojansky (roji) 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.

Thanks, LGTM!

{
IncludeVectors = includeVectors,
VectorPropertyName = "DescriptionEmbedding",
VectorProperty = r => "DescriptionEmbedding",

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.

Suggested change
VectorProperty = r => "DescriptionEmbedding",
VectorProperty = r => r.DescriptionEmbedding,

new()
{
VectorPropertyName = "DescriptionEmbedding",
VectorProperty = r => "DescriptionEmbedding",

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.

Suggested change
VectorProperty = r => "DescriptionEmbedding",
VectorProperty = r => r.DescriptionEmbedding,

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 see a few other tests are also returning a string instead of selecting the prop

throw new InvalidOperationException($"The property {property.Name} of {typeof(TRecord).FullName} is not a Vector property.");
}

throw new InvalidOperationException("The expression must be a a valid Vector property access.");

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.

Suggested change
throw new InvalidOperationException("The expression must be a a valid Vector property access.");
throw new InvalidOperationException("The expression must be a a valid Vector property accessor.");

#pragma warning restore CS0618 // Type or member is obsolete
if (!string.IsNullOrEmpty(obsoletePropertyName))
{
return obsoletePropertyName!;

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.

We are missing some validation here, to ensure that the name is actually referring to a vector property.
In some connectors I see we are subsequently calling GetProperty, but it would only check that the property exists, not that it is a vector. Not checking upfront might lead to poor error messaging later if we just pass the name down to the SDK and let it throw.

In my branch I'm adding a propertyreader method that deals with this checking, so we could hold off until mine is merged and then use that here too.

#pragma warning restore CS0618 // Type or member is obsolete
};

Assert.Equal(ExpectedName, sut.GetVectorPropertyName(searchOptions));

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 should actually fail in the same way that it would if using the property selection expression.

}
}

return this._vectorProperties.Count > 0

@westey-m westey (westey-m) Mar 5, 2025 •

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.

We want to throw here if the user didn't specify a property and more than 1 exists. This is a change from the current behavior, but I'm adding it to my change doc.

}

[Fact]
public void GetVectorPropertyNameReturnsFirstVectorPropertyWhenNoPropertySpecified()

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 should actually fail, since first is not necessarily deterministic.

if (!this._storagePropertyNames.TryGetValue(vectorDataModelPropertyName, out var vectorPropertyName))
{
throw new InvalidOperationException("The collection does not have any vector properties, so vector search is not possible.");
throw new InvalidOperationException($"The collection does not have a vector field named '{vectorDataModelPropertyName}'.");

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.

It would be nice to just verify this in GetVectorPropertyName.

Comment on lines +227 to +228
var vectorProperty = this._propertyReader.GetProperty<VectorStoreRecordVectorProperty>(this._propertyReader.GetVectorPropertyName(internalOptions));
var vectorPropertyName = vectorProperty.DataModelPropertyName;

@westey-m westey (westey-m) Mar 5, 2025 •

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._propertyReader.GetVectorPropertyName(internalOptions) already returns DataModelPropertyName. However in GetVectorPropertyName we are typically looking through the list if Properties to get the right vector property.
Consider just returning the vector property from GetVectorPropertyName and then the caller can read its DataModelPropertyName or whatever other property is required.

…o vectorSearchSelector

# Conflicts:
#	dotnet/src/Connectors/VectorData.Abstractions/VectorSearch/VectorSearchOptions.cs
/// </value>
public string? VectorPropertyName { get; init; }

/// <summary>

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.

Adam Sitnik (@adamsitnik) did I see correctly that you removed the [Obsolete] from VectorPropertyName just above? Don't we want to obsolete it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Shay Rojansky (@roji) great catch! It must have been removed during the merge (xml docs were updated), I am going to add it back of course.

@adamsitnik

Copy link
Copy Markdown
Member Author

Closing, I've sent a new PR for that that handles HybridSerarch as well: #10850

This branch had an error being deployed

1 failed deployment
integration — 3a236ddd Deployed Mar 6, 2025 by adamsitnik
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernel Issues or pull requests impacting the core kernel memory .NET Issue or Pull requests regarding .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants