Skip to content

Commit

Permalink
.Net: Add filtering support for VectoreStoreTextSearch (#8947)
Browse files Browse the repository at this point in the history
### Motivation and Context

Related to #6725 

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [ ] The code builds clean without any errors or warnings
- [ ] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄
  • Loading branch information
markwallace-microsoft authored Sep 24, 2024
1 parent 21f8a27 commit d6b6019
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ public sealed class VectorSearchFilter
/// </summary>
public IEnumerable<FilterClause> FilterClauses => this._filterClauses;

/// <summary>
/// Create an instance of <see cref="VectorSearchFilter"/>
/// </summary>
public VectorSearchFilter()
{
}

/// <summary>
/// Create an instance of <see cref="VectorSearchFilter"/> with the provided <see cref="FilterClause"/>s.
/// <param name="filterClauses">The <see cref="FilterClause"/> instances to use</param>
/// </summary>
internal VectorSearchFilter(IEnumerable<FilterClause> filterClauses)
{
Verify.NotNull(filterClauses, nameof(filterClauses));

this._filterClauses.AddRange(filterClauses);
}

/// <summary>
/// Add an equal to clause to the filter options.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private async Task<IAsyncEnumerable<VectorSearchResult<TRecord>>> ExecuteVectorS
searchOptions ??= new TextSearchOptions();
var vectorSearchOptions = new VectorSearchOptions
{
Filter = null,
Filter = searchOptions.Filter?.FilterClauses is not null ? new VectorSearchFilter(searchOptions.Filter.FilterClauses) : null,
Offset = searchOptions.Offset,
Limit = searchOptions.Count,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,47 @@ public async Task CanGetSearchResultsWithVectorizableTextSearchAsync()
Assert.Equal(2, results.Count);
}

[Fact]
public async Task CanFilterGetSearchResultsWithVectorizedSearchAsync()
{
// Arrange.
var sut = await CreateVectorStoreTextSearchFromVectorizedSearchAsync();
TextSearchFilter evenFilter = new();
evenFilter.Equality("Tag", "Even");
TextSearchFilter oddFilter = new();
oddFilter.Equality("Tag", "Odd");

// Act.
KernelSearchResults<object> evenSearchResults = await sut.GetSearchResultsAsync("What is the Semantic Kernel?", new()
{
Count = 2,
Offset = 0,
Filter = evenFilter
});
var evenResults = await ToListAsync(evenSearchResults.Results);
KernelSearchResults<object> oddSearchResults = await sut.GetSearchResultsAsync("What is the Semantic Kernel?", new()
{
Count = 2,
Offset = 0,
Filter = oddFilter
});
var oddResults = await ToListAsync(oddSearchResults.Results);

Assert.Equal(2, evenResults.Count);
var result1 = evenResults[0] as DataModel;
Assert.Equal("Even", result1?.Tag);
var result2 = evenResults[1] as DataModel;
Assert.Equal("Even", result2?.Tag);

Assert.Equal(2, oddResults.Count);
result1 = oddResults[0] as DataModel;
Assert.Equal("Odd", result1?.Tag);
result2 = oddResults[1] as DataModel;
Assert.Equal("Odd", result2?.Tag);
}

#region private

/// <summary>
/// Create a <see cref="VectorStoreTextSearch{TRecord}"/> from a <see cref="IVectorizedSearch{TRecord}"/>.
/// </summary>
Expand Down Expand Up @@ -185,6 +226,7 @@ private static async Task AddRecordsAsync(
{
Key = Guid.NewGuid(),
Text = $"Record {i}",
Tag = i % 2 == 0 ? "Even" : "Odd",
Embedding = await embeddingService.GenerateEmbeddingAsync($"Record {i}")
};
await recordCollection.UpsertAsync(dataModel);
Expand Down Expand Up @@ -274,7 +316,12 @@ private sealed class DataModel
[VectorStoreRecordData]
public required string Text { get; init; }

[VectorStoreRecordData(IsFilterable = true)]
public required string Tag { get; init; }

[VectorStoreRecordVector(1536)]
public ReadOnlyMemory<float> Embedding { get; init; }
}

#endregion
}

0 comments on commit d6b6019

Please sign in to comment.