Skip to content

Commit 28ad57a

Browse files
committed
Work on VectorStoreTextSearch
1 parent f69c0c1 commit 28ad57a

File tree

13 files changed

+192
-255
lines changed

13 files changed

+192
-255
lines changed

dotnet/samples/Demos/OnnxSimpleRAG/Program.cs

+3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ await collection.UpsertAsync(new InformationItem()
6464
}
6565

6666
// Add a plugin to search the database with.
67+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the InMemoryVectorStore above instead of passing it here.
68+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
6769
var vectorStoreTextSearch = new VectorStoreTextSearch<InformationItem>(collection, embeddingService);
70+
#pragma warning restore CS0618
6871
kernel.Plugins.Add(vectorStoreTextSearch.CreateWithSearch("SearchPlugin"));
6972

7073
// Start the conversation

dotnet/samples/GettingStartedWithTextSearch/Step4_Search_With_VectorStore.cs

+19-10
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@ public async Task UsingInMemoryVectorStoreRecordTextSearchAsync()
2424
{
2525
// Use embedding generation service and record collection for the fixture.
2626
var textEmbeddingGeneration = fixture.TextEmbeddingGenerationService;
27-
var vectorizedSearch = fixture.VectorStoreRecordCollection;
27+
var collection = fixture.VectorStoreRecordCollection;
2828

2929
// Create a text search instance using the InMemory vector store.
30-
var textSearch = new VectorStoreTextSearch<DataModel>(vectorizedSearch, textEmbeddingGeneration);
30+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the collection
31+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
32+
var textSearch = new VectorStoreTextSearch<DataModel>(collection, textEmbeddingGeneration);
33+
#pragma warning restore CS0618
3134

3235
// Search and return results as TextSearchResult items
3336
var query = "What is the Semantic Kernel?";
@@ -57,10 +60,13 @@ public async Task RagWithInMemoryVectorStoreTextSearchAsync()
5760

5861
// Use embedding generation service and record collection for the fixture.
5962
var textEmbeddingGeneration = fixture.TextEmbeddingGenerationService;
60-
var vectorizedSearch = fixture.VectorStoreRecordCollection;
63+
var collection = fixture.VectorStoreRecordCollection;
6164

6265
// Create a text search instance using the InMemory vector store.
63-
var textSearch = new VectorStoreTextSearch<DataModel>(vectorizedSearch, textEmbeddingGeneration);
66+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the collection
67+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
68+
var textSearch = new VectorStoreTextSearch<DataModel>(collection, textEmbeddingGeneration);
69+
#pragma warning restore CS0618
6470

6571
// Build a text search plugin with vector store search and add to the kernel
6672
var searchPlugin = textSearch.CreateWithGetTextSearchResults("SearchPlugin");
@@ -69,14 +75,14 @@ public async Task RagWithInMemoryVectorStoreTextSearchAsync()
6975
// Invoke prompt and use text search plugin to provide grounding information
7076
var query = "What is the Semantic Kernel?";
7177
string promptTemplate = """
72-
{{#with (SearchPlugin-GetTextSearchResults query)}}
73-
{{#each this}}
78+
{{#with (SearchPlugin-GetTextSearchResults query)}}
79+
{{#each this}}
7480
Name: {{Name}}
7581
Value: {{Value}}
7682
Link: {{Link}}
7783
-----------------
78-
{{/each}}
79-
{{/with}}
84+
{{/each}}
85+
{{/with}}
8086
8187
{{query}}
8288
@@ -108,10 +114,13 @@ public async Task FunctionCallingWithInMemoryVectorStoreTextSearchAsync()
108114

109115
// Use embedding generation service and record collection for the fixture.
110116
var textEmbeddingGeneration = fixture.TextEmbeddingGenerationService;
111-
var vectorizedSearch = fixture.VectorStoreRecordCollection;
117+
var collection = fixture.VectorStoreRecordCollection;
112118

113119
// Create a text search instance using the InMemory vector store.
114-
var textSearch = new VectorStoreTextSearch<DataModel>(vectorizedSearch, textEmbeddingGeneration);
120+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the collection
121+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
122+
var textSearch = new VectorStoreTextSearch<DataModel>(collection, textEmbeddingGeneration);
123+
#pragma warning restore CS0618
115124

116125
// Build a text search plugin with vector store search and add to the kernel
117126
var searchPlugin = textSearch.CreateWithGetTextSearchResults("SearchPlugin");

dotnet/src/IntegrationTests/Connectors/Memory/AzureAISearch/AzureAISearchTextSearchTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3-
#if DISABLED
4-
53
using System;
64
using System.Threading.Tasks;
75
using Azure.Identity;
@@ -87,7 +85,11 @@ public override Task<ITextSearch> CreateTextSearchAsync()
8785
var stringMapper = new HotelTextSearchStringMapper();
8886
var resultMapper = new HotelTextSearchResultMapper();
8987

88+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the AzureAISearchVectorStore above instead of passing it here.
89+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
9090
var result = new VectorStoreTextSearch<AzureAISearchHotel>(vectorSearch, this.EmbeddingGenerator!, stringMapper, resultMapper);
91+
#pragma warning restore CS0618
92+
9193
return Task.FromResult<ITextSearch>(result);
9294
}
9395

@@ -144,5 +146,3 @@ public TextSearchResult MapFromResultToTextSearchResult(object result)
144146
}
145147
}
146148
}
147-
148-
#endif

dotnet/src/IntegrationTests/Connectors/Memory/InMemory/InMemoryVectorStoreTextSearchTests.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3-
#if DISABLED
4-
53
using System;
64
using System.Threading.Tasks;
75
using Microsoft.Extensions.Configuration;
@@ -52,7 +50,10 @@ static DataModel CreateRecord(int index, string text, ReadOnlyMemory<float> embe
5250
var stringMapper = new DataModelTextSearchStringMapper();
5351
var resultMapper = new DataModelTextSearchResultMapper();
5452

53+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the InMemoryVectorStore above instead of passing it here.
54+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
5555
return new VectorStoreTextSearch<DataModel>(vectorSearch, this.EmbeddingGenerator!, stringMapper, resultMapper);
56+
#pragma warning restore CS0618
5657
}
5758

5859
/// <inheritdoc/>
@@ -76,5 +77,3 @@ public override bool VerifySearchResults(object[] results, string query, TextSea
7677
return true;
7778
}
7879
}
79-
80-
#endif

dotnet/src/IntegrationTests/Connectors/Memory/Qdrant/QdrantTextSearchTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3-
#if DISABLED
4-
53
using System;
64
using System.Threading.Tasks;
75
using Microsoft.SemanticKernel.Connectors.Qdrant;
@@ -36,7 +34,11 @@ public override Task<ITextSearch> CreateTextSearchAsync()
3634
var stringMapper = new HotelInfoTextSearchStringMapper();
3735
var resultMapper = new HotelInfoTextSearchResultMapper();
3836

37+
// TODO: Once OpenAITextEmbeddingGenerationService implements MEAI's IEmbeddingGenerator (#10811), configure it with the AzureAISearchVectorStore above instead of passing it here.
38+
#pragma warning disable CS0618 // VectorStoreTextSearch with ITextEmbeddingGenerationService is obsolete
3939
var result = new VectorStoreTextSearch<HotelInfo>(vectorSearch, this.EmbeddingGenerator!, stringMapper, resultMapper);
40+
#pragma warning restore CS0618
41+
4042
return Task.FromResult<ITextSearch>(result);
4143
}
4244

@@ -93,5 +95,3 @@ public TextSearchResult MapFromResultToTextSearchResult(object result)
9395
}
9496
}
9597
}
96-
97-
#endif

dotnet/src/IntegrationTests/Data/BaseVectorStoreTextSearchTests.cs

-32
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3-
#if DISABLED
4-
53
using System;
64
using System.Collections.Generic;
75
using System.Collections.ObjectModel;
86
using System.IO;
9-
using System.Runtime.CompilerServices;
107
using System.Threading;
118
using System.Threading.Tasks;
129
using Microsoft.Extensions.Configuration;
@@ -100,33 +97,6 @@ public Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string>
10097
}
10198
}
10299

103-
/// <summary>
104-
/// Decorator for a <see cref="IVectorSearch{TRecord}"/> that generates embeddings for text search queries.
105-
/// </summary>
106-
protected sealed class VectorizedSearchWrapper<TRecord>(IVectorSearch<TRecord> vectorizedSearch, ITextEmbeddingGenerationService textEmbeddingGeneration) : IVectorizableTextSearch<TRecord>
107-
{
108-
/// <inheritdoc/>
109-
public async IAsyncEnumerable<VectorSearchResult<TRecord>> VectorizableTextSearchAsync(string searchText, int top, VectorSearchOptions<TRecord>? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
110-
{
111-
var vectorizedQuery = await textEmbeddingGeneration!.GenerateEmbeddingAsync(searchText, cancellationToken: cancellationToken).ConfigureAwait(false);
112-
113-
await foreach (var result in vectorizedSearch.VectorizedSearchAsync(vectorizedQuery, top, options, cancellationToken))
114-
{
115-
yield return result;
116-
}
117-
}
118-
119-
/// <inheritdoc />
120-
public object? GetService(Type serviceType, object? serviceKey = null)
121-
{
122-
ArgumentNullException.ThrowIfNull(serviceType);
123-
124-
return
125-
serviceKey is null && serviceType.IsInstanceOfType(this) ? this :
126-
vectorizedSearch.GetService(serviceType, serviceKey);
127-
}
128-
}
129-
130100
/// <summary>
131101
/// Sample model class that represents a record entry.
132102
/// </summary>
@@ -154,5 +124,3 @@ protected sealed class DataModel
154124
public ReadOnlyMemory<float> Embedding { get; init; }
155125
}
156126
}
157-
158-
#endif

dotnet/src/SemanticKernel.AotTests/Program.cs

-2
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,9 @@ private static async Task<int> Main(string[] args)
5757
KernelBuilderPluginsExtensionsTests.AddFromType,
5858
KernelBuilderPluginsExtensionsTests.AddFromObject,
5959

60-
#if DISABLED
6160
// Tests for text search
6261
VectorStoreTextSearchTests.GetTextSearchResultsAsync,
6362
VectorStoreTextSearchTests.AddVectorStoreTextSearch,
64-
#endif
6563

6664
TextSearchExtensionsTests.CreateWithSearch,
6765
TextSearchExtensionsTests.CreateWithGetTextSearchResults,

dotnet/src/SemanticKernel.AotTests/UnitTests/Search/VectorStoreTextSearchTests.cs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3-
#if DISABLED
4-
53
using Microsoft.Extensions.DependencyInjection;
64
using Microsoft.Extensions.VectorData;
75
using Microsoft.SemanticKernel;
@@ -48,7 +46,7 @@ public static async Task AddVectorStoreTextSearch()
4846
};
4947
var vectorizableTextSearch = new MockVectorizableTextSearch<DataModel>(testData);
5048
var serviceCollection = new ServiceCollection();
51-
serviceCollection.AddSingleton<IVectorizableTextSearch<DataModel>>(vectorizableTextSearch);
49+
serviceCollection.AddSingleton<IVectorSearch<DataModel>>(vectorizableTextSearch);
5250

5351
// Act
5452
serviceCollection.AddVectorStoreTextSearch<DataModel>();
@@ -84,5 +82,3 @@ private sealed class DataModel
8482
public required string Link { get; init; }
8583
}
8684
}
87-
88-
#endif

dotnet/src/SemanticKernel.Core/Data/TextSearch/TextSearchServiceCollectionExtensions.cs

+14-31
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,10 @@ public static class TextSearchServiceCollectionExtensions
4040
options ??= sp.GetService<VectorStoreTextSearchOptions>();
4141

4242
var vectorSearch = sp.GetService<IVectorSearch<TRecord>>();
43-
if (vectorSearch is not null)
44-
{
45-
return new VectorStoreTextSearch<TRecord>(
46-
vectorSearch,
47-
stringMapper,
48-
resultMapper,
49-
options);
50-
}
51-
52-
var vectorizedSearch = sp.GetService<IVectorSearch<TRecord>>();
53-
var generationService = sp.GetService<ITextEmbeddingGenerationService>();
54-
if (vectorizedSearch is not null && generationService is not null)
55-
{
56-
return new VectorStoreTextSearch<TRecord>(
57-
vectorizedSearch,
58-
generationService,
59-
stringMapper,
60-
resultMapper,
61-
options);
62-
}
6343

64-
throw new InvalidOperationException("No IVectorizableTextSearch<TRecord> or IVectorizedSearch<TRecord> and ITextEmbeddingGenerationService registered.");
44+
return vectorSearch is null
45+
? throw new InvalidOperationException("No IVectorSearch<TRecord> registered.")
46+
: new VectorStoreTextSearch<TRecord>(vectorSearch, stringMapper, resultMapper, options);
6547
});
6648

6749
return services;
@@ -71,14 +53,14 @@ public static class TextSearchServiceCollectionExtensions
7153
/// Register a <see cref="VectorStoreTextSearch{TRecord}"/> instance with the specified service ID.
7254
/// </summary>
7355
/// <param name="services">The <see cref="IServiceCollection"/> to register the <see cref="ITextSearch"/> on.</param>
74-
/// <param name="vectorizableTextSearchServiceId">Service id of the <see cref="IVectorizableTextSearch{TRecord}"/> to use.</param>
56+
/// <param name="vectorSearchServiceId">Service id of the <see cref="IVectorizableTextSearch{TRecord}"/> to use.</param>
7557
/// <param name="stringMapper"><see cref="ITextSearchStringMapper" /> instance that can map a TRecord to a <see cref="string"/></param>
7658
/// <param name="resultMapper"><see cref="ITextSearchResultMapper" /> instance that can map a TRecord to a <see cref="TextSearchResult"/></param>
7759
/// <param name="options">Options used to construct an instance of <see cref="VectorStoreTextSearch{TRecord}"/></param>
7860
/// <param name="serviceId">An optional service id to use as the service key.</param>
7961
public static IServiceCollection AddVectorStoreTextSearch<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TRecord>(
8062
this IServiceCollection services,
81-
string vectorizableTextSearchServiceId,
63+
string vectorSearchServiceId,
8264
ITextSearchStringMapper? stringMapper = null,
8365
ITextSearchResultMapper? resultMapper = null,
8466
VectorStoreTextSearchOptions? options = null,
@@ -95,17 +77,17 @@ public static class TextSearchServiceCollectionExtensions
9577
resultMapper ??= sp.GetService<ITextSearchResultMapper>();
9678
options ??= sp.GetService<VectorStoreTextSearchOptions>();
9779

98-
var vectorizableTextSearch = sp.GetKeyedService<IVectorSearch<TRecord>>(vectorizableTextSearchServiceId);
99-
if (vectorizableTextSearch is not null)
80+
var vectorSearch = sp.GetKeyedService<IVectorSearch<TRecord>>(vectorSearchServiceId);
81+
if (vectorSearch is not null)
10082
{
10183
return new VectorStoreTextSearch<TRecord>(
102-
vectorizableTextSearch,
84+
vectorSearch,
10385
stringMapper,
10486
resultMapper,
10587
options);
10688
}
10789

108-
throw new InvalidOperationException($"No IVectorizableTextSearch<TRecord> for service id {vectorizableTextSearchServiceId} registered.");
90+
throw new InvalidOperationException($"No IVectorSearch<TRecord> for service id {vectorSearchServiceId} registered.");
10991
});
11092

11193
return services;
@@ -115,15 +97,16 @@ public static class TextSearchServiceCollectionExtensions
11597
/// Register a <see cref="VectorStoreTextSearch{TRecord}"/> instance with the specified service ID.
11698
/// </summary>
11799
/// <param name="services">The <see cref="IServiceCollection"/> to register the <see cref="ITextSearch"/> on.</param>
118-
/// <param name="vectorizedSearchServiceId">Service id of the <see cref="IVectorSearch{TRecord}"/> to use.</param>
100+
/// <param name="vectorSearchServiceId">Service id of the <see cref="IVectorSearch{TRecord}"/> to use.</param>
119101
/// <param name="textEmbeddingGenerationServiceId">Service id of the <see cref="ITextEmbeddingGenerationService"/> to use.</param>
120102
/// <param name="stringMapper"><see cref="ITextSearchStringMapper" /> instance that can map a TRecord to a <see cref="string"/></param>
121103
/// <param name="resultMapper"><see cref="ITextSearchResultMapper" /> instance that can map a TRecord to a <see cref="TextSearchResult"/></param>
122104
/// <param name="options">Options used to construct an instance of <see cref="VectorStoreTextSearch{TRecord}"/></param>
123105
/// <param name="serviceId">An optional service id to use as the service key.</param>
106+
[Obsolete("Use the overload which doesn't accept a textEmbeddingGenerationServiceId, and configure an IEmbeddingGenerator instead with the collection represented by vectorSearchServiceId.")]
124107
public static IServiceCollection AddVectorStoreTextSearch<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TRecord>(
125108
this IServiceCollection services,
126-
string vectorizedSearchServiceId,
109+
string vectorSearchServiceId,
127110
string textEmbeddingGenerationServiceId,
128111
ITextSearchStringMapper? stringMapper = null,
129112
ITextSearchResultMapper? resultMapper = null,
@@ -141,10 +124,10 @@ public static class TextSearchServiceCollectionExtensions
141124
resultMapper ??= sp.GetService<ITextSearchResultMapper>();
142125
options ??= sp.GetService<VectorStoreTextSearchOptions>();
143126

144-
var vectorizedSearch = sp.GetKeyedService<IVectorSearch<TRecord>>(vectorizedSearchServiceId);
127+
var vectorizedSearch = sp.GetKeyedService<IVectorSearch<TRecord>>(vectorSearchServiceId);
145128
if (vectorizedSearch is null)
146129
{
147-
throw new InvalidOperationException($"No IVectorizedSearch<TRecord> for service id {vectorizedSearchServiceId} registered.");
130+
throw new InvalidOperationException($"No IVectorizedSearch<TRecord> for service id {vectorSearchServiceId} registered.");
148131
}
149132

150133
var generationService = sp.GetKeyedService<ITextEmbeddingGenerationService>(textEmbeddingGenerationServiceId);

0 commit comments

Comments
 (0)