Skip to content

Commit 54f7f7d

Browse files
committed
arch: Implement dual interface pattern for text search filtering
- Remove LINQ dependency from non-generic ITextSearch interface - Revert non-generic methods to direct VectorSearchFilter usage - Eliminates IL3051 warnings by avoiding RequiresDynamicCode on non-generic interface - Preserves backward compatibility with legacy TextSearchFilter path - Maintains modern LINQ expressions for generic ITextSearch<TRecord> interface Architectural separation: - Non-generic: TextSearchOptions → VectorSearchFilter (legacy path) - Generic: TextSearchOptions<TRecord> → Expression<Func<TRecord, bool>> (LINQ path) Resolves remaining IL3051 compilation errors while maintaining Issue #10456 objectives.
1 parent 78fe164 commit 54f7f7d

File tree

1 file changed

+8
-22
lines changed

1 file changed

+8
-22
lines changed

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

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ public VectorStoreTextSearch(
174174
}
175175

176176
/// <inheritdoc/>
177-
[RequiresDynamicCode("Calls Microsoft.SemanticKernel.Data.VectorStoreTextSearch<TRecord>.ConvertTextSearchFilterToLinq(TextSearchFilter).")]
178177
public Task<KernelSearchResults<string>> SearchAsync(string query, TextSearchOptions? searchOptions = null, CancellationToken cancellationToken = default)
179178
{
180179
var searchResponse = this.ExecuteVectorSearchAsync(query, searchOptions, cancellationToken);
@@ -183,7 +182,6 @@ public Task<KernelSearchResults<string>> SearchAsync(string query, TextSearchOpt
183182
}
184183

185184
/// <inheritdoc/>
186-
[RequiresDynamicCode("Calls Microsoft.SemanticKernel.Data.VectorStoreTextSearch<TRecord>.ConvertTextSearchFilterToLinq(TextSearchFilter).")]
187185
public Task<KernelSearchResults<TextSearchResult>> GetTextSearchResultsAsync(string query, TextSearchOptions? searchOptions = null, CancellationToken cancellationToken = default)
188186
{
189187
var searchResponse = this.ExecuteVectorSearchAsync(query, searchOptions, cancellationToken);
@@ -192,7 +190,6 @@ public Task<KernelSearchResults<TextSearchResult>> GetTextSearchResultsAsync(str
192190
}
193191

194192
/// <inheritdoc/>
195-
[RequiresDynamicCode("Calls Microsoft.SemanticKernel.Data.VectorStoreTextSearch<TRecord>.ConvertTextSearchFilterToLinq(TextSearchFilter).")]
196193
public Task<KernelSearchResults<object>> GetSearchResultsAsync(string query, TextSearchOptions? searchOptions = null, CancellationToken cancellationToken = default)
197194
{
198195
var searchResponse = this.ExecuteVectorSearchAsync(query, searchOptions, cancellationToken);
@@ -201,6 +198,7 @@ public Task<KernelSearchResults<object>> GetSearchResultsAsync(string query, Tex
201198
}
202199

203200
/// <inheritdoc/>
201+
[RequiresDynamicCode("LINQ filtering over generic types requires dynamic code generation for expression trees.")]
204202
Task<KernelSearchResults<string>> ITextSearch<TRecord>.SearchAsync(string query, TextSearchOptions<TRecord>? searchOptions, CancellationToken cancellationToken)
205203
{
206204
var searchResponse = this.ExecuteVectorSearchAsync(query, searchOptions, cancellationToken);
@@ -209,6 +207,7 @@ Task<KernelSearchResults<string>> ITextSearch<TRecord>.SearchAsync(string query,
209207
}
210208

211209
/// <inheritdoc/>
210+
[RequiresDynamicCode("LINQ filtering over generic types requires dynamic code generation for expression trees.")]
212211
Task<KernelSearchResults<TextSearchResult>> ITextSearch<TRecord>.GetTextSearchResultsAsync(string query, TextSearchOptions<TRecord>? searchOptions, CancellationToken cancellationToken)
213212
{
214213
var searchResponse = this.ExecuteVectorSearchAsync(query, searchOptions, cancellationToken);
@@ -217,6 +216,7 @@ Task<KernelSearchResults<TextSearchResult>> ITextSearch<TRecord>.GetTextSearchRe
217216
}
218217

219218
/// <inheritdoc/>
219+
[RequiresDynamicCode("LINQ filtering over generic types requires dynamic code generation for expression trees.")]
220220
Task<KernelSearchResults<object>> ITextSearch<TRecord>.GetSearchResultsAsync(string query, TextSearchOptions<TRecord>? searchOptions, CancellationToken cancellationToken)
221221
{
222222
var searchResponse = this.ExecuteVectorSearchAsync(query, searchOptions, cancellationToken);
@@ -274,35 +274,21 @@ private TextSearchStringMapper CreateTextSearchStringMapper()
274274
}
275275

276276
/// <summary>
277-
/// Execute a vector search and return the results.
277+
/// Execute a vector search and return the results using legacy filtering for backward compatibility.
278278
/// </summary>
279279
/// <param name="query">What to search for.</param>
280-
/// <param name="searchOptions">Search options.</param>
280+
/// <param name="searchOptions">Search options with legacy TextSearchFilter.</param>
281281
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
282-
[RequiresDynamicCode("Calls Microsoft.SemanticKernel.Data.VectorStoreTextSearch<TRecord>.ConvertTextSearchFilterToLinq(TextSearchFilter)")]
283282
private async IAsyncEnumerable<VectorSearchResult<TRecord>> ExecuteVectorSearchAsync(string query, TextSearchOptions? searchOptions, [EnumeratorCancellation] CancellationToken cancellationToken)
284283
{
285284
searchOptions ??= new TextSearchOptions();
286-
287-
var linqFilter = ConvertTextSearchFilterToLinq(searchOptions.Filter);
288285
var vectorSearchOptions = new VectorSearchOptions<TRecord>
289286
{
290-
Skip = searchOptions.Skip,
291-
};
292-
293-
// Use modern LINQ filtering if conversion was successful
294-
if (linqFilter != null)
295-
{
296-
vectorSearchOptions.Filter = linqFilter;
297-
}
298-
else if (searchOptions.Filter?.FilterClauses != null && searchOptions.Filter.FilterClauses.Any())
299-
{
300-
// For complex filters that couldn't be converted to LINQ,
301-
// fall back to the legacy approach but with minimal overhead
302287
#pragma warning disable CS0618 // VectorSearchFilter is obsolete
303-
vectorSearchOptions.OldFilter = new VectorSearchFilter(searchOptions.Filter.FilterClauses);
288+
OldFilter = searchOptions.Filter?.FilterClauses is not null ? new VectorSearchFilter(searchOptions.Filter.FilterClauses) : null,
304289
#pragma warning restore CS0618 // VectorSearchFilter is obsolete
305-
}
290+
Skip = searchOptions.Skip,
291+
};
306292

307293
await foreach (var result in this.ExecuteVectorSearchCoreAsync(query, vectorSearchOptions, searchOptions.Top, cancellationToken).ConfigureAwait(false))
308294
{

0 commit comments

Comments
 (0)