diff --git a/dotnet/samples/GettingStartedWithTextSearch/Step1_Web_Search.cs b/dotnet/samples/GettingStartedWithTextSearch/Step1_Web_Search.cs index a5676b9f1c5d..fe33e7f7da10 100644 --- a/dotnet/samples/GettingStartedWithTextSearch/Step1_Web_Search.cs +++ b/dotnet/samples/GettingStartedWithTextSearch/Step1_Web_Search.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete - Sample demonstrates legacy interface usage + using Microsoft.SemanticKernel.Data; using Microsoft.SemanticKernel.Plugins.Web.Bing; using Microsoft.SemanticKernel.Plugins.Web.Google; diff --git a/dotnet/samples/GettingStartedWithTextSearch/Step2_Search_For_RAG.cs b/dotnet/samples/GettingStartedWithTextSearch/Step2_Search_For_RAG.cs index cb21cccc66b4..1278f8a59141 100644 --- a/dotnet/samples/GettingStartedWithTextSearch/Step2_Search_For_RAG.cs +++ b/dotnet/samples/GettingStartedWithTextSearch/Step2_Search_For_RAG.cs @@ -1,4 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. + +#pragma warning disable CS0618 // ITextSearch is obsolete - Sample demonstrates legacy interface usage + using System.Text.RegularExpressions; using HtmlAgilityPack; using Microsoft.SemanticKernel; diff --git a/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/AgentWithTextSearchProviderConformance/AgentWithTextSearchProvider.cs b/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/AgentWithTextSearchProviderConformance/AgentWithTextSearchProvider.cs index 4d350564b7de..89e0a1790648 100644 --- a/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/AgentWithTextSearchProviderConformance/AgentWithTextSearchProvider.cs +++ b/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/AgentWithTextSearchProviderConformance/AgentWithTextSearchProvider.cs @@ -41,7 +41,9 @@ public abstract class AgentWithTextSearchProvider(Func creat public async Task TextSearchBehaviorStateIsUsedByAgentInternalAsync(string question, string expectedResult, params string[] ragResults) { // Arrange +#pragma warning disable CS0618 // ITextSearch is obsolete - Testing legacy interface var mockTextSearch = new Mock(); +#pragma warning restore CS0618 mockTextSearch.Setup(x => x.GetTextSearchResultsAsync( It.IsAny(), It.IsAny(), diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchTextSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchTextSearchTests.cs index aaf65fa5cb4a..9280df1f513c 100644 --- a/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.Threading.Tasks; using Azure.AI.OpenAI; diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/InMemory/InMemoryVectorStoreTextSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/InMemory/InMemoryVectorStoreTextSearchTests.cs index a5f6c4e6ec4c..cf41f187dca3 100644 --- a/dotnet/src/IntegrationTests/Connectors/Memory/InMemory/InMemoryVectorStoreTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Connectors/Memory/InMemory/InMemoryVectorStoreTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.Threading.Tasks; using Microsoft.Extensions.AI; diff --git a/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantTextSearchTests.cs b/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantTextSearchTests.cs index 5a1619138472..5f02d94c4022 100644 --- a/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.Threading.Tasks; using Microsoft.SemanticKernel.Connectors.Qdrant; diff --git a/dotnet/src/IntegrationTests/Data/BaseTextSearchTests.cs b/dotnet/src/IntegrationTests/Data/BaseTextSearchTests.cs index 5e7716bcfb3e..3e598f6d546b 100644 --- a/dotnet/src/IntegrationTests/Data/BaseTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Data/BaseTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // Type or member is obsolete - Testing legacy non-generic ITextSearch interface + using System; using System.Collections.Generic; using System.Linq; diff --git a/dotnet/src/IntegrationTests/Plugins/Web/Bing/BingTextSearchTests.cs b/dotnet/src/IntegrationTests/Plugins/Web/Bing/BingTextSearchTests.cs index 34550d130459..bc418182682b 100644 --- a/dotnet/src/IntegrationTests/Plugins/Web/Bing/BingTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Plugins/Web/Bing/BingTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.SemanticKernel.Data; diff --git a/dotnet/src/IntegrationTests/Plugins/Web/Google/GoogleTextSearchTests.cs b/dotnet/src/IntegrationTests/Plugins/Web/Google/GoogleTextSearchTests.cs index 73244ce75d8b..1bf0ba48a232 100644 --- a/dotnet/src/IntegrationTests/Plugins/Web/Google/GoogleTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Plugins/Web/Google/GoogleTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.SemanticKernel.Data; diff --git a/dotnet/src/IntegrationTests/Plugins/Web/Tavily/TavilyTextSearchTests.cs b/dotnet/src/IntegrationTests/Plugins/Web/Tavily/TavilyTextSearchTests.cs index ffc0e066b8d4..77529b8fe1c5 100644 --- a/dotnet/src/IntegrationTests/Plugins/Web/Tavily/TavilyTextSearchTests.cs +++ b/dotnet/src/IntegrationTests/Plugins/Web/Tavily/TavilyTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.SemanticKernel.Data; diff --git a/dotnet/src/Plugins/Plugins.UnitTests/Web/Bing/BingTextSearchTests.cs b/dotnet/src/Plugins/Plugins.UnitTests/Web/Bing/BingTextSearchTests.cs index a6172e334314..4fad54261338 100644 --- a/dotnet/src/Plugins/Plugins.UnitTests/Web/Bing/BingTextSearchTests.cs +++ b/dotnet/src/Plugins/Plugins.UnitTests/Web/Bing/BingTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.IO; using System.Linq; diff --git a/dotnet/src/Plugins/Plugins.UnitTests/Web/Brave/BraveTextSearchTests.cs b/dotnet/src/Plugins/Plugins.UnitTests/Web/Brave/BraveTextSearchTests.cs index 8a98a3d81a47..0435df46a31d 100644 --- a/dotnet/src/Plugins/Plugins.UnitTests/Web/Brave/BraveTextSearchTests.cs +++ b/dotnet/src/Plugins/Plugins.UnitTests/Web/Brave/BraveTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.IO; using System.Linq; diff --git a/dotnet/src/Plugins/Plugins.UnitTests/Web/Google/GoogleTextSearchTests.cs b/dotnet/src/Plugins/Plugins.UnitTests/Web/Google/GoogleTextSearchTests.cs index 1d97ae8ec26b..38a497eac9d1 100644 --- a/dotnet/src/Plugins/Plugins.UnitTests/Web/Google/GoogleTextSearchTests.cs +++ b/dotnet/src/Plugins/Plugins.UnitTests/Web/Google/GoogleTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.IO; using System.Linq; diff --git a/dotnet/src/Plugins/Plugins.UnitTests/Web/Tavily/TavilyTextSearchTests.cs b/dotnet/src/Plugins/Plugins.UnitTests/Web/Tavily/TavilyTextSearchTests.cs index 553290a4287d..f510d0555168 100644 --- a/dotnet/src/Plugins/Plugins.UnitTests/Web/Tavily/TavilyTextSearchTests.cs +++ b/dotnet/src/Plugins/Plugins.UnitTests/Web/Tavily/TavilyTextSearchTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete + using System; using System.IO; using System.Linq; diff --git a/dotnet/src/Plugins/Plugins.Web/Bing/BingTextSearch.cs b/dotnet/src/Plugins/Plugins.Web/Bing/BingTextSearch.cs index 556e04f148d3..34b5db97917a 100644 --- a/dotnet/src/Plugins/Plugins.Web/Bing/BingTextSearch.cs +++ b/dotnet/src/Plugins/Plugins.Web/Bing/BingTextSearch.cs @@ -20,7 +20,9 @@ namespace Microsoft.SemanticKernel.Plugins.Web.Bing; /// /// A Bing Text Search implementation that can be used to perform searches using the Bing Web Search API. /// +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility public sealed class BingTextSearch : ITextSearch +#pragma warning restore CS0618 { /// /// Create an instance of the with API key authentication. diff --git a/dotnet/src/Plugins/Plugins.Web/Brave/BraveTextSearch.cs b/dotnet/src/Plugins/Plugins.Web/Brave/BraveTextSearch.cs index 8fa793ea4efb..af54b42f704c 100644 --- a/dotnet/src/Plugins/Plugins.Web/Brave/BraveTextSearch.cs +++ b/dotnet/src/Plugins/Plugins.Web/Brave/BraveTextSearch.cs @@ -20,7 +20,9 @@ namespace Microsoft.SemanticKernel.Plugins.Web.Brave; /// /// A Brave Text Search implementation that can be used to perform searches using the Brave Web Search API. /// +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility public sealed class BraveTextSearch : ITextSearch +#pragma warning restore CS0618 { /// /// Create an instance of the with API key authentication. diff --git a/dotnet/src/Plugins/Plugins.Web/Google/GoogleTextSearch.cs b/dotnet/src/Plugins/Plugins.Web/Google/GoogleTextSearch.cs index c4165a2edadc..38b2a705ed42 100644 --- a/dotnet/src/Plugins/Plugins.Web/Google/GoogleTextSearch.cs +++ b/dotnet/src/Plugins/Plugins.Web/Google/GoogleTextSearch.cs @@ -17,7 +17,9 @@ namespace Microsoft.SemanticKernel.Plugins.Web.Google; /// /// A Google Text Search implementation that can be used to perform searches using the Google Web Search API. /// +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility public sealed class GoogleTextSearch : ITextSearch, IDisposable +#pragma warning restore CS0618 { /// /// Initializes a new instance of the class. diff --git a/dotnet/src/Plugins/Plugins.Web/Tavily/TavilyTextSearch.cs b/dotnet/src/Plugins/Plugins.Web/Tavily/TavilyTextSearch.cs index 4e01d0ffb88b..a7ddacab3469 100644 --- a/dotnet/src/Plugins/Plugins.Web/Tavily/TavilyTextSearch.cs +++ b/dotnet/src/Plugins/Plugins.Web/Tavily/TavilyTextSearch.cs @@ -20,7 +20,9 @@ namespace Microsoft.SemanticKernel.Plugins.Web.Tavily; /// /// A Tavily Text Search implementation that can be used to perform searches using the Tavily Web Search API. /// +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility public sealed class TavilyTextSearch : ITextSearch +#pragma warning restore CS0618 { /// /// Create an instance of the with API key authentication. diff --git a/dotnet/src/Plugins/Plugins.Web/WebServiceCollectionExtensions.cs b/dotnet/src/Plugins/Plugins.Web/WebServiceCollectionExtensions.cs index e534ad5d2399..d4d004f70170 100644 --- a/dotnet/src/Plugins/Plugins.Web/WebServiceCollectionExtensions.cs +++ b/dotnet/src/Plugins/Plugins.Web/WebServiceCollectionExtensions.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete - these extension methods provide backward compatibility + using Microsoft.Extensions.DependencyInjection; using Microsoft.SemanticKernel.Data; using Microsoft.SemanticKernel.Plugins.Web.Bing; diff --git a/dotnet/src/SemanticKernel.Abstractions/Data/TextSearch/ITextSearch.cs b/dotnet/src/SemanticKernel.Abstractions/Data/TextSearch/ITextSearch.cs index 667e4e1a6a37..57da1a9ec677 100644 --- a/dotnet/src/SemanticKernel.Abstractions/Data/TextSearch/ITextSearch.cs +++ b/dotnet/src/SemanticKernel.Abstractions/Data/TextSearch/ITextSearch.cs @@ -49,7 +49,9 @@ Task> GetSearchResultsAsync( /// /// Interface for text based search queries for use with Semantic Kernel prompts and automatic function calling. +/// This non-generic interface uses legacy for backward compatibility. /// +[System.Obsolete("Use ITextSearch with LINQ-based filtering instead. This interface will be removed in a future version.")] public interface ITextSearch { /// diff --git a/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/MockTextSearch.cs b/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/MockTextSearch.cs index 72aa218239f9..9ed0d43a87fa 100644 --- a/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/MockTextSearch.cs +++ b/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/MockTextSearch.cs @@ -4,7 +4,9 @@ namespace SemanticKernel.AotTests.UnitTests.Search; +#pragma warning disable CS0618 // Type or member is obsolete internal sealed class MockTextSearch : ITextSearch +#pragma warning restore CS0618 // Type or member is obsolete { private readonly KernelSearchResults? _objectResults; private readonly KernelSearchResults? _textSearchResults; diff --git a/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/TextSearchExtensionsTests.cs b/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/TextSearchExtensionsTests.cs index 8aff74675ecf..163b0294f5c1 100644 --- a/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/TextSearchExtensionsTests.cs +++ b/dotnet/src/SemanticKernel.AotTests/UnitTests/Search/TextSearchExtensionsTests.cs @@ -21,7 +21,9 @@ public static async Task CreateWithSearch() // Arrange var testData = new List { "test-value" }; KernelSearchResults results = new(testData.ToAsyncEnumerable()); +#pragma warning disable CS0618 // Type or member is obsolete ITextSearch textSearch = new MockTextSearch(results); +#pragma warning restore CS0618 // Type or member is obsolete // Act var plugin = textSearch.CreateWithSearch("SearchPlugin", s_jsonSerializerOptions); @@ -35,7 +37,9 @@ public static async Task CreateWithGetTextSearchResults() // Arrange var testData = new List { new("test-value") }; KernelSearchResults results = new(testData.ToAsyncEnumerable()); +#pragma warning disable CS0618 // Type or member is obsolete ITextSearch textSearch = new MockTextSearch(results); +#pragma warning restore CS0618 // Type or member is obsolete // Act var plugin = textSearch.CreateWithGetTextSearchResults("SearchPlugin", s_jsonSerializerOptions); @@ -49,7 +53,9 @@ public static async Task CreateWithGetSearchResults() // Arrange var testData = new List { new("test-value") }; KernelSearchResults results = new(testData.ToAsyncEnumerable()); +#pragma warning disable CS0618 // Type or member is obsolete ITextSearch textSearch = new MockTextSearch(results); +#pragma warning restore CS0618 // Type or member is obsolete // Act var plugin = textSearch.CreateWithGetSearchResults("SearchPlugin", s_jsonSerializerOptions); diff --git a/dotnet/src/SemanticKernel.Core/Data/TextSearch/TextSearchExtensions.cs b/dotnet/src/SemanticKernel.Core/Data/TextSearch/TextSearchExtensions.cs index bfb829c44759..c326b939dca2 100644 --- a/dotnet/src/SemanticKernel.Core/Data/TextSearch/TextSearchExtensions.cs +++ b/dotnet/src/SemanticKernel.Core/Data/TextSearch/TextSearchExtensions.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete - these extension methods provide backward compatibility + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; diff --git a/dotnet/src/SemanticKernel.Core/Data/TextSearch/VectorStoreTextSearch.cs b/dotnet/src/SemanticKernel.Core/Data/TextSearch/VectorStoreTextSearch.cs index 26c43ea1db31..121ff9b6c7bb 100644 --- a/dotnet/src/SemanticKernel.Core/Data/TextSearch/VectorStoreTextSearch.cs +++ b/dotnet/src/SemanticKernel.Core/Data/TextSearch/VectorStoreTextSearch.cs @@ -16,7 +16,9 @@ namespace Microsoft.SemanticKernel.Data; /// A Vector Store Text Search implementation that can be used to perform searches using a . /// [Experimental("SKEXP0001")] +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility public sealed class VectorStoreTextSearch<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TRecord> : ITextSearch, ITextSearch +#pragma warning restore CS0618 #pragma warning restore CA1711 // Identifiers should not have incorrect suffix { /// @@ -268,19 +270,22 @@ private TextSearchStringMapper CreateTextSearchStringMapper() } /// - /// Execute a vector search and return the results. + /// Execute a vector search and return the results using legacy filtering for backward compatibility. /// /// What to search for. - /// Search options. + /// Search options with legacy TextSearchFilter. /// The to monitor for cancellation requests. The default is . private async IAsyncEnumerable> ExecuteVectorSearchAsync(string query, TextSearchOptions? searchOptions, [EnumeratorCancellation] CancellationToken cancellationToken) { searchOptions ??= new TextSearchOptions(); + var vectorSearchOptions = new VectorSearchOptions { #pragma warning disable CS0618 // VectorSearchFilter is obsolete - OldFilter = searchOptions.Filter?.FilterClauses is not null ? new VectorSearchFilter(searchOptions.Filter.FilterClauses) : null, -#pragma warning restore CS0618 // VectorSearchFilter is obsolete + OldFilter = searchOptions.Filter?.FilterClauses is not null + ? new VectorSearchFilter(searchOptions.Filter.FilterClauses) + : null, +#pragma warning restore CS0618 Skip = searchOptions.Skip, }; diff --git a/dotnet/src/SemanticKernel.Core/Data/TextSearchBehavior/TextSearchProvider.cs b/dotnet/src/SemanticKernel.Core/Data/TextSearchBehavior/TextSearchProvider.cs index 6ee680d91826..fe6a9f7d0d35 100644 --- a/dotnet/src/SemanticKernel.Core/Data/TextSearchBehavior/TextSearchProvider.cs +++ b/dotnet/src/SemanticKernel.Core/Data/TextSearchBehavior/TextSearchProvider.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility + using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/dotnet/src/SemanticKernel.Core/Data/TextSearchStore/TextSearchStore.cs b/dotnet/src/SemanticKernel.Core/Data/TextSearchStore/TextSearchStore.cs index ed2314eb8b1e..d1d22aacab34 100644 --- a/dotnet/src/SemanticKernel.Core/Data/TextSearchStore/TextSearchStore.cs +++ b/dotnet/src/SemanticKernel.Core/Data/TextSearchStore/TextSearchStore.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // ITextSearch is obsolete - this class provides backward compatibility + using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/dotnet/src/SemanticKernel.UnitTests/Data/MockTextSearch.cs b/dotnet/src/SemanticKernel.UnitTests/Data/MockTextSearch.cs index 916b158fc770..01746adf623e 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Data/MockTextSearch.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Data/MockTextSearch.cs @@ -10,7 +10,9 @@ namespace SemanticKernel.UnitTests.Data; /// /// Mock implementation of /// +#pragma warning disable CS0618 // Type or member is obsolete internal sealed class MockTextSearch(int count = 3, long totalCount = 30) : ITextSearch +#pragma warning restore CS0618 // Type or member is obsolete { /// public Task> GetSearchResultsAsync(string query, TextSearchOptions? searchOptions = null, CancellationToken cancellationToken = default) diff --git a/dotnet/src/SemanticKernel.UnitTests/Data/TextSearchProviderTests.cs b/dotnet/src/SemanticKernel.UnitTests/Data/TextSearchProviderTests.cs index 28d37124a3c9..c552a426d272 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Data/TextSearchProviderTests.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Data/TextSearchProviderTests.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#pragma warning disable CS0618 // Type or member is obsolete - Testing legacy non-generic ITextSearch interface + using System; using System.Collections.Generic; using System.Linq; diff --git a/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTestBase.cs b/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTestBase.cs index ec0134936f3f..066cf7ef2398 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTestBase.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTestBase.cs @@ -140,6 +140,7 @@ public string MapFromResultToString(object result) { DataModel dataModel => dataModel.Text, DataModelWithRawEmbedding dataModelWithRawEmbedding => dataModelWithRawEmbedding.Text, + DataModelWithTags dataModelWithTags => dataModelWithTags.Text, _ => throw new ArgumentException("Invalid result type.") }; } @@ -155,6 +156,7 @@ public TextSearchResult MapFromResultToTextSearchResult(object result) { DataModel dataModel => new TextSearchResult(value: dataModel.Text) { Name = dataModel.Key.ToString() }, DataModelWithRawEmbedding dataModelWithRawEmbedding => new TextSearchResult(value: dataModelWithRawEmbedding.Text) { Name = dataModelWithRawEmbedding.Key.ToString() }, + DataModelWithTags dataModelWithTags => new TextSearchResult(value: dataModelWithTags.Text) { Name = dataModelWithTags.Key.ToString() }, _ => throw new ArgumentException("Invalid result type.") }; } @@ -231,4 +233,27 @@ public sealed class DataModelWithRawEmbedding [VectorStoreVector(1536)] public ReadOnlyMemory Embedding { get; init; } } + + /// + /// Sample model class for testing collection-based filtering (AnyTagEqualTo). + /// +#pragma warning disable CA1812 // Avoid uninstantiated internal classes + public sealed class DataModelWithTags +#pragma warning restore CA1812 // Avoid uninstantiated internal classes + { + [VectorStoreKey] + public Guid Key { get; init; } + + [VectorStoreData] + public required string Text { get; init; } + + [VectorStoreData(IsIndexed = true)] + public required string Tag { get; init; } + + [VectorStoreData(IsIndexed = true)] + public required IReadOnlyList Tags { get; init; } + + [VectorStoreVector(1536)] + public string? Embedding { get; init; } + } } diff --git a/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTests.cs b/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTests.cs index 66803cc86f53..8dd095710c06 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTests.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Data/VectorStoreTextSearchTests.cs @@ -9,6 +9,7 @@ using Xunit; namespace SemanticKernel.UnitTests.Data; + public class VectorStoreTextSearchTests : VectorStoreTextSearchTestBase { #pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete @@ -203,4 +204,222 @@ public async Task CanFilterGetSearchResultsWithVectorizedSearchAsync() result2 = oddResults[1] as DataModel; Assert.Equal("Odd", result2?.Tag); } + + #region Generic Interface Tests (ITextSearch) + + [Fact] + public async Task LinqSearchAsync() + { + // Arrange - Create VectorStoreTextSearch (implements both interfaces) + var sut = await CreateVectorStoreTextSearchAsync(); + + // Cast to ITextSearch to use type-safe LINQ filtering + ITextSearch typeSafeInterface = sut; + + // Act - Use generic interface with LINQ filter + var searchOptions = new TextSearchOptions + { + Top = 5, + Filter = r => r.Tag == "Even" + }; + + KernelSearchResults searchResults = await typeSafeInterface.SearchAsync( + "What is the Semantic Kernel?", + searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert - Should return results (filtering applied at vector store level) + Assert.NotEmpty(results); + } + + [Fact] + public async Task LinqGetTextSearchResultsAsync() + { + // Arrange + var sut = await CreateVectorStoreTextSearchAsync(); + ITextSearch typeSafeInterface = sut; + + // Act - Use generic interface with LINQ filter + var searchOptions = new TextSearchOptions + { + Top = 5, + Filter = r => r.Tag == "Odd" + }; + + KernelSearchResults searchResults = await typeSafeInterface.GetTextSearchResultsAsync( + "What is the Semantic Kernel?", + searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert + Assert.NotEmpty(results); + Assert.All(results, result => Assert.NotNull(result.Value)); + } + + [Fact] + public async Task LinqGetSearchResultsAsync() + { + // Arrange + var sut = await CreateVectorStoreTextSearchAsync(); + ITextSearch typeSafeInterface = sut; + + // Act - Use type-safe LINQ filtering with ITextSearch + var searchOptions = new TextSearchOptions + { + Top = 5, + Filter = r => r.Tag == "Even" + }; + + KernelSearchResults searchResults = await typeSafeInterface.GetSearchResultsAsync( + "What is the Semantic Kernel?", + searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert - Results should be DataModel objects with Tag == "Even" + Assert.NotEmpty(results); + Assert.All(results, result => + { + var dataModel = Assert.IsType(result); + Assert.Equal("Even", dataModel.Tag); + }); + } + + [Fact] + public async Task LinqFilterSimpleEqualityAsync() + { + // Arrange + var sut = await CreateVectorStoreTextSearchAsync(); + ITextSearch typeSafeInterface = sut; + + // Act - Simple equality filter + var searchOptions = new TextSearchOptions + { + Top = 10, + Filter = r => r.Tag == "Odd" + }; + + var searchResults = await typeSafeInterface.GetSearchResultsAsync("test", searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert - All results should have Tag == "Odd" + Assert.NotEmpty(results); + Assert.All(results.Cast(), dm => Assert.Equal("Odd", dm.Tag)); + } + + [Fact] + public async Task LinqFilterComplexExpressionAsync() + { + // Arrange + var sut = await CreateVectorStoreTextSearchAsync(); + ITextSearch typeSafeInterface = sut; + + // Act - Complex LINQ expression with multiple conditions + var searchOptions = new TextSearchOptions + { + Top = 10, + Filter = r => r.Tag == "Even" && r.Text.Contains("Record") + }; + + var searchResults = await typeSafeInterface.GetSearchResultsAsync("test", searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert - Results should match both conditions + Assert.NotEmpty(results); + Assert.All(results.Cast(), dm => + { + Assert.Equal("Even", dm.Tag); + Assert.Contains("Record", dm.Text); + }); + } + + [Fact] + public async Task LinqFilterCollectionContainsAsync() + { + // Arrange - Create collection with DataModelWithTags + using var embeddingGenerator = new MockTextEmbeddingGenerator(); + using var vectorStore = new InMemoryVectorStore(new() { EmbeddingGenerator = embeddingGenerator }); + var collection = vectorStore.GetCollection("records"); + await collection.EnsureCollectionExistsAsync(); + + // Add test records with tags + var records = new[] + { + new DataModelWithTags + { + Key = Guid.NewGuid(), + Text = "First", + Tag = "test", + Tags = new[] { "important", "urgent" }, + Embedding = "First" + }, + new DataModelWithTags + { + Key = Guid.NewGuid(), + Text = "Second", + Tag = "test", + Tags = new[] { "normal", "routine" }, + Embedding = "Second" + }, + new DataModelWithTags + { + Key = Guid.NewGuid(), + Text = "Third", + Tag = "test", + Tags = new[] { "important", "routine" }, + Embedding = "Third" + } + }; + + foreach (var record in records) + { + await collection.UpsertAsync(record); + } + + var textSearch = new VectorStoreTextSearch( + collection, + new DataModelTextSearchStringMapper(), + new DataModelTextSearchResultMapper()); + + ITextSearch typeSafeInterface = textSearch; + + // Act - Use LINQ .Contains() for collection filtering + var searchOptions = new TextSearchOptions + { + Top = 10, + Filter = r => r.Tags.Contains("important") + }; + + var searchResults = await typeSafeInterface.GetSearchResultsAsync("test", searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert - Should return 2 records with "important" tag + Assert.Equal(2, results.Count); + Assert.All(results.Cast(), dm => + Assert.Contains("important", dm.Tags)); + } + + [Fact] + public async Task LinqFilterNullReturnsAllResultsAsync() + { + // Arrange + var sut = await CreateVectorStoreTextSearchAsync(); + ITextSearch typeSafeInterface = sut; + + // Act - Use generic interface with null filter + var searchOptions = new TextSearchOptions + { + Top = 10, + Filter = null // No filter + }; + + var searchResults = await typeSafeInterface.GetSearchResultsAsync("test", searchOptions); + var results = await searchResults.Results.ToListAsync(); + + // Assert - Should return both "Even" and "Odd" records + var dataModels = results.Cast().ToList(); + Assert.Contains(dataModels, dm => dm.Tag == "Even"); + Assert.Contains(dataModels, dm => dm.Tag == "Odd"); + } + + #endregion }