From 652446d81b5dbbdc876fd5e2fd32d0594ab87070 Mon Sep 17 00:00:00 2001 From: alexmg Date: Mon, 4 Nov 2024 17:22:31 +1000 Subject: [PATCH 1/5] Add setting to enable SessionId on SearchOptions in AzureAISearchMemory --- .../tests/Evaluation.Tests/appsettings.json | 6 +- .../002-dotnet-Serverless/appsettings.json | 6 +- .../210-KM-without-builder/appsettings.json | 6 +- examples/401-evaluation/appsettings.json | 6 +- .../AzureAISearch/AzureAISearchConfig.cs | 7 +++ .../AzureAISearch/AzureAISearchMemory.cs | 63 ++++++++++--------- .../Core.FunctionalTests/appsettings.json | 6 +- .../Services/AzureAISearch.cs | 2 + 8 files changed, 66 insertions(+), 36 deletions(-) diff --git a/applications/tests/Evaluation.Tests/appsettings.json b/applications/tests/Evaluation.Tests/appsettings.json index 6b9c02d2d..9048c8f0e 100644 --- a/applications/tests/Evaluation.Tests/appsettings.json +++ b/applications/tests/Evaluation.Tests/appsettings.json @@ -70,7 +70,11 @@ "APIKey": "", // Hybrid search is not enabled by default. Note that when using hybrid search // relevance scores are different, usually lower, than when using just vector search - "UseHybridSearch": false + "UseHybridSearch": false, + // Helps improve relevance score consistency for search services with multiple replicas by + // attempting to route a given request to the same replica for that session. Use this when + // favoring consistent scoring over lower latency. + "UseSessionId": false }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/examples/002-dotnet-Serverless/appsettings.json b/examples/002-dotnet-Serverless/appsettings.json index 8e060a1df..750382c18 100644 --- a/examples/002-dotnet-Serverless/appsettings.json +++ b/examples/002-dotnet-Serverless/appsettings.json @@ -70,7 +70,11 @@ "APIKey": "", // Hybrid search is not enabled by default. Note that when using hybrid search // relevance scores are different, usually lower, than when using just vector search - "UseHybridSearch": false + "UseHybridSearch": false, + // Helps improve relevance score consistency for search services with multiple replicas by + // attempting to route a given request to the same replica for that session. Use this when + // favoring consistent scoring over lower latency. + "UseSessionId": false }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/examples/210-KM-without-builder/appsettings.json b/examples/210-KM-without-builder/appsettings.json index 83857dd2c..add04b5a4 100644 --- a/examples/210-KM-without-builder/appsettings.json +++ b/examples/210-KM-without-builder/appsettings.json @@ -248,7 +248,11 @@ "APIKey": "", // Hybrid search is not enabled by default. Note that when using hybrid search // relevance scores are different, usually lower, than when using just vector search - "UseHybridSearch": false + "UseHybridSearch": false, + // Helps improve relevance score consistency for search services with multiple replicas by + // attempting to route a given request to the same replica for that session. Use this when + // favoring consistent scoring over lower latency. + "UseSessionId": false }, "AzureAIDocIntel": { // "APIKey" or "AzureIdentity". diff --git a/examples/401-evaluation/appsettings.json b/examples/401-evaluation/appsettings.json index 1bb5005d3..7b0fba6a5 100644 --- a/examples/401-evaluation/appsettings.json +++ b/examples/401-evaluation/appsettings.json @@ -70,7 +70,11 @@ "APIKey": "", // Hybrid search is not enabled by default. Note that when using hybrid search // relevance scores are different, usually lower, than when using just vector search - "UseHybridSearch": false + "UseHybridSearch": false, + // Helps improve relevance score consistency for search services with multiple replicas by + // attempting to route a given request to the same replica for that session. Use this when + // favoring consistent scoring over lower latency. + "UseSessionId": false }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs index d9023ab68..9adfbd5c5 100644 --- a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs +++ b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs @@ -31,6 +31,13 @@ public enum AuthTypes /// public bool UseHybridSearch { get; set; } = false; + /// + /// Helps improve relevance score consistency for search services with multiple replicas by + /// attempting to route a given request to the same replica for that session. Use this when + /// favoring consistent scoring over lower latency. + /// + public bool UseSessionId { get; set; } = false; + public void SetCredential(TokenCredential credential) { this.Auth = AuthTypes.ManualTokenCredential; diff --git a/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs b/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs index 82e28e5c7..4e63a624a 100644 --- a/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs +++ b/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs @@ -34,6 +34,7 @@ public class AzureAISearchMemory : IMemoryDb, IMemoryDbUpsertBatch private readonly ITextEmbeddingGenerator _embeddingGenerator; private readonly ILogger _log; private readonly bool _useHybridSearch; + private readonly bool _useSessionId; /// /// Create a new instance @@ -49,6 +50,7 @@ public AzureAISearchMemory( this._embeddingGenerator = embeddingGenerator; this._log = (loggerFactory ?? DefaultLogger.Factory).CreateLogger(); this._useHybridSearch = config.UseHybridSearch; + this._useSessionId = config.UseSessionId; if (string.IsNullOrEmpty(config.Endpoint)) { @@ -190,7 +192,7 @@ await client.IndexDocumentsAsync( FilterMode = VectorFilterMode.PreFilter } }; - DefineFieldsToSelect(options, withEmbeddings); + this.ApplyCommonSearchOptions(options, withEmbeddings, filters); if (limit > 0) { @@ -199,15 +201,6 @@ await client.IndexDocumentsAsync( this._log.LogDebug("KNearestNeighborsCount and max results: {0}", limit); } - // Remove empty filters - filters = filters?.Where(f => !f.IsEmpty()).ToList(); - - if (filters is { Count: > 0 }) - { - options.Filter = AzureAISearchFiltering.BuildSearchFilter(filters); - this._log.LogDebug("Filtering vectors, condition: {0}", options.Filter); - } - Response>? searchResult = null; try { @@ -254,7 +247,7 @@ public async IAsyncEnumerable GetListAsync( var client = this.GetSearchClient(index); SearchOptions options = new(); - DefineFieldsToSelect(options, withEmbeddings); + this.ApplyCommonSearchOptions(options, withEmbeddings, filters); if (limit > 0) { @@ -262,25 +255,6 @@ public async IAsyncEnumerable GetListAsync( this._log.LogDebug("Max results: {0}", limit); } - // Remove empty filters - filters = filters?.Where(f => !f.IsEmpty()).ToList(); - - if (filters is { Count: > 0 }) - { - options.Filter = AzureAISearchFiltering.BuildSearchFilter(filters); - this._log.LogDebug("Filtering vectors, condition: {0}", options.Filter); - } - - // See: https://learn.microsoft.com/azure/search/search-query-understand-collection-filters - // fieldValue = fieldValue.Replace("'", "''", StringComparison.Ordinal); - // var options = new SearchOptions - // { - // Filter = fieldIsCollection - // ? $"{fieldName}/any(s: s eq '{fieldValue}')" - // : $"{fieldName} eq '{fieldValue}')", - // Size = limit - // }; - Response>? searchResult = null; try { @@ -627,7 +601,10 @@ at Azure.Search.Documents.SearchClient.SearchInternal[T](SearchOptions options, return indexSchema; } - private static void DefineFieldsToSelect(SearchOptions options, bool withEmbeddings) + private void ApplyCommonSearchOptions( + SearchOptions options, + bool withEmbeddings, + ICollection? filters = null) { options.Select.Add(AzureAISearchMemoryRecord.IdField); options.Select.Add(AzureAISearchMemoryRecord.TagsField); @@ -636,6 +613,30 @@ private static void DefineFieldsToSelect(SearchOptions options, bool withEmbeddi { options.Select.Add(AzureAISearchMemoryRecord.VectorField); } + + // Remove empty filters + filters = filters?.Where(f => !f.IsEmpty()).ToList(); + + if (filters is { Count: > 0 }) + { + options.Filter = AzureAISearchFiltering.BuildSearchFilter(filters); + this._log.LogDebug("Filtering vectors, condition: {0}", options.Filter); + } + + // See: https://learn.microsoft.com/azure/search/search-query-understand-collection-filters + // fieldValue = fieldValue.Replace("'", "''", StringComparison.Ordinal); + // var options = new SearchOptions + // { + // Filter = fieldIsCollection + // ? $"{fieldName}/any(s: s eq '{fieldValue}')" + // : $"{fieldName} eq '{fieldValue}')", + // Size = limit + // }; + + if (this._useSessionId) + { + options.SessionId = Guid.NewGuid().ToString("N"); + } } private static double ScoreToCosineSimilarity(double score) diff --git a/service/tests/Core.FunctionalTests/appsettings.json b/service/tests/Core.FunctionalTests/appsettings.json index 2b0e90b31..bb9127616 100644 --- a/service/tests/Core.FunctionalTests/appsettings.json +++ b/service/tests/Core.FunctionalTests/appsettings.json @@ -12,7 +12,11 @@ "Auth": "AzureIdentity", "Endpoint": "https://<...>", "APIKey": "", - "UseHybridSearch": false + "UseHybridSearch": false, + // Helps improve relevance score consistency for search services with multiple replicas by + // attempting to route a given request to the same replica for that session. Use this when + // favoring consistent scoring over lower latency. + "UseSessionId": false }, "LlamaSharp": { "TextModel": { diff --git a/tools/InteractiveSetup/Services/AzureAISearch.cs b/tools/InteractiveSetup/Services/AzureAISearch.cs index 15962c2e4..92c2bac18 100644 --- a/tools/InteractiveSetup/Services/AzureAISearch.cs +++ b/tools/InteractiveSetup/Services/AzureAISearch.cs @@ -22,6 +22,7 @@ public static void Setup(Context ctx, bool force = false) { "Auth", "ApiKey" }, { "APIKey", "" }, { "UseHybridSearch", false }, + { "UseSessionId", false } }; } @@ -45,5 +46,6 @@ public static void Setup(Context ctx, bool force = false) AppSettings.Change(x => x.Services[ServiceName]["Endpoint"] = SetupUI.AskOpenQuestion("Azure AI Search ", config["Endpoint"].ToString())); AppSettings.Change(x => x.Services[ServiceName]["UseHybridSearch"] = SetupUI.AskBoolean("Use hybrid search (yes/no)?", (bool)config["UseHybridSearch"])); + AppSettings.Change(x => x.Services[ServiceName]["UseSessionId"] = SetupUI.AskBoolean("Use session ID (yes/no)?", (bool)config["UseSessionId"])); } } From 475e58457bba6944ea5e5b1cae33b3452918ea1c Mon Sep 17 00:00:00 2001 From: Devis Lucato Date: Tue, 12 Nov 2024 10:44:23 -0800 Subject: [PATCH 2/5] Update comments --- .../tests/Evaluation.Tests/appsettings.json | 9 ++++++++- examples/002-dotnet-Serverless/appsettings.json | 9 ++++++++- examples/210-KM-without-builder/appsettings.json | 9 ++++++++- examples/401-evaluation/appsettings.json | 9 ++++++++- .../AzureAISearch/AzureAISearchConfig.cs | 9 ++++++++- service/Service/appsettings.json | 13 ++++++++++++- service/tests/Core.FunctionalTests/appsettings.json | 6 +----- 7 files changed, 53 insertions(+), 11 deletions(-) diff --git a/applications/tests/Evaluation.Tests/appsettings.json b/applications/tests/Evaluation.Tests/appsettings.json index 9048c8f0e..427e80689 100644 --- a/applications/tests/Evaluation.Tests/appsettings.json +++ b/applications/tests/Evaluation.Tests/appsettings.json @@ -73,7 +73,14 @@ "UseHybridSearch": false, // Helps improve relevance score consistency for search services with multiple replicas by // attempting to route a given request to the same replica for that session. Use this when - // favoring consistent scoring over lower latency. + // favoring consistent scoring over lower latency. Can adversely affect performance. + // + // Whether to use sticky sessions, which can help getting more consistent results. + // When using sticky sessions, a best-effort attempt will be made to target the same replica set. + // Be wary that reusing the same replica repeatedly can interfere with the load balancing of + // the requests across replicas and adversely affect the performance of the search service. + // + // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body "UseSessionId": false }, "OpenAI": { diff --git a/examples/002-dotnet-Serverless/appsettings.json b/examples/002-dotnet-Serverless/appsettings.json index 750382c18..9a3928101 100644 --- a/examples/002-dotnet-Serverless/appsettings.json +++ b/examples/002-dotnet-Serverless/appsettings.json @@ -73,7 +73,14 @@ "UseHybridSearch": false, // Helps improve relevance score consistency for search services with multiple replicas by // attempting to route a given request to the same replica for that session. Use this when - // favoring consistent scoring over lower latency. + // favoring consistent scoring over lower latency. Can adversely affect performance. + // + // Whether to use sticky sessions, which can help getting more consistent results. + // When using sticky sessions, a best-effort attempt will be made to target the same replica set. + // Be wary that reusing the same replica repeatedly can interfere with the load balancing of + // the requests across replicas and adversely affect the performance of the search service. + // + // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body "UseSessionId": false }, "OpenAI": { diff --git a/examples/210-KM-without-builder/appsettings.json b/examples/210-KM-without-builder/appsettings.json index add04b5a4..ea4fbce0b 100644 --- a/examples/210-KM-without-builder/appsettings.json +++ b/examples/210-KM-without-builder/appsettings.json @@ -251,7 +251,14 @@ "UseHybridSearch": false, // Helps improve relevance score consistency for search services with multiple replicas by // attempting to route a given request to the same replica for that session. Use this when - // favoring consistent scoring over lower latency. + // favoring consistent scoring over lower latency. Can adversely affect performance. + // + // Whether to use sticky sessions, which can help getting more consistent results. + // When using sticky sessions, a best-effort attempt will be made to target the same replica set. + // Be wary that reusing the same replica repeatedly can interfere with the load balancing of + // the requests across replicas and adversely affect the performance of the search service. + // + // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body "UseSessionId": false }, "AzureAIDocIntel": { diff --git a/examples/401-evaluation/appsettings.json b/examples/401-evaluation/appsettings.json index 7b0fba6a5..31bed71a6 100644 --- a/examples/401-evaluation/appsettings.json +++ b/examples/401-evaluation/appsettings.json @@ -73,7 +73,14 @@ "UseHybridSearch": false, // Helps improve relevance score consistency for search services with multiple replicas by // attempting to route a given request to the same replica for that session. Use this when - // favoring consistent scoring over lower latency. + // favoring consistent scoring over lower latency. Can adversely affect performance. + // + // Whether to use sticky sessions, which can help getting more consistent results. + // When using sticky sessions, a best-effort attempt will be made to target the same replica set. + // Be wary that reusing the same replica repeatedly can interfere with the load balancing of + // the requests across replicas and adversely affect the performance of the search service. + // + // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body "UseSessionId": false }, "OpenAI": { diff --git a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs index 9adfbd5c5..d90f61e89 100644 --- a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs +++ b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs @@ -34,7 +34,14 @@ public enum AuthTypes /// /// Helps improve relevance score consistency for search services with multiple replicas by /// attempting to route a given request to the same replica for that session. Use this when - /// favoring consistent scoring over lower latency. + /// favoring consistent scoring over lower latency. Can adversely affect performance. + /// + /// Whether to use sticky sessions, which can help getting more consistent results. + /// When using sticky sessions, a best-effort attempt will be made to target the same replica set. + /// Be wary that reusing the same replica repeatedly can interfere with the load balancing of + /// the requests across replicas and adversely affect the performance of the search service. + /// + /// See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body /// public bool UseSessionId { get; set; } = false; diff --git a/service/Service/appsettings.json b/service/Service/appsettings.json index 49da0a3fb..b040adbdd 100644 --- a/service/Service/appsettings.json +++ b/service/Service/appsettings.json @@ -280,7 +280,18 @@ "APIKey": "", // Hybrid search is not enabled by default. Note that when using hybrid search // relevance scores are different, usually lower, than when using just vector search - "UseHybridSearch": false + "UseHybridSearch": false, + // Helps improve relevance score consistency for search services with multiple replicas by + // attempting to route a given request to the same replica for that session. Use this when + // favoring consistent scoring over lower latency. Can adversely affect performance. + // + // Whether to use sticky sessions, which can help getting more consistent results. + // When using sticky sessions, a best-effort attempt will be made to target the same replica set. + // Be wary that reusing the same replica repeatedly can interfere with the load balancing of + // the requests across replicas and adversely affect the performance of the search service. + // + // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body + "UseSessionId": false }, "AzureAIDocIntel": { // "APIKey" or "AzureIdentity". diff --git a/service/tests/Core.FunctionalTests/appsettings.json b/service/tests/Core.FunctionalTests/appsettings.json index bb9127616..2b0e90b31 100644 --- a/service/tests/Core.FunctionalTests/appsettings.json +++ b/service/tests/Core.FunctionalTests/appsettings.json @@ -12,11 +12,7 @@ "Auth": "AzureIdentity", "Endpoint": "https://<...>", "APIKey": "", - "UseHybridSearch": false, - // Helps improve relevance score consistency for search services with multiple replicas by - // attempting to route a given request to the same replica for that session. Use this when - // favoring consistent scoring over lower latency. - "UseSessionId": false + "UseHybridSearch": false }, "LlamaSharp": { "TextModel": { From 32d3793f5fd2cca07d2fffd2d3039d3d6480a487 Mon Sep 17 00:00:00 2001 From: Devis Lucato Date: Tue, 12 Nov 2024 11:14:17 -0800 Subject: [PATCH 3/5] Rename UseSessionId to UseStickySessions + refactoring --- .../tests/Evaluation.Tests/appsettings.json | 2 +- .../002-dotnet-Serverless/appsettings.json | 2 +- .../210-KM-without-builder/appsettings.json | 2 +- examples/401-evaluation/appsettings.json | 2 +- .../appsettings.json | 3 +- .../AzureAISearch/AzureAISearchConfig.cs | 2 +- .../AzureAISearch/AzureAISearchMemory.cs | 41 +++++++++++-------- service/Service/appsettings.json | 2 +- .../Core.FunctionalTests/appsettings.json | 3 +- .../Services/AzureAISearch.cs | 4 +- 10 files changed, 36 insertions(+), 27 deletions(-) diff --git a/applications/tests/Evaluation.Tests/appsettings.json b/applications/tests/Evaluation.Tests/appsettings.json index 427e80689..f5fa9abe3 100644 --- a/applications/tests/Evaluation.Tests/appsettings.json +++ b/applications/tests/Evaluation.Tests/appsettings.json @@ -81,7 +81,7 @@ // the requests across replicas and adversely affect the performance of the search service. // // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body - "UseSessionId": false + "UseStickySessions": false }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/examples/002-dotnet-Serverless/appsettings.json b/examples/002-dotnet-Serverless/appsettings.json index 9a3928101..c4a64ce23 100644 --- a/examples/002-dotnet-Serverless/appsettings.json +++ b/examples/002-dotnet-Serverless/appsettings.json @@ -81,7 +81,7 @@ // the requests across replicas and adversely affect the performance of the search service. // // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body - "UseSessionId": false + "UseStickySessions": false }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/examples/210-KM-without-builder/appsettings.json b/examples/210-KM-without-builder/appsettings.json index ea4fbce0b..331025b97 100644 --- a/examples/210-KM-without-builder/appsettings.json +++ b/examples/210-KM-without-builder/appsettings.json @@ -259,7 +259,7 @@ // the requests across replicas and adversely affect the performance of the search service. // // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body - "UseSessionId": false + "UseStickySessions": false }, "AzureAIDocIntel": { // "APIKey" or "AzureIdentity". diff --git a/examples/401-evaluation/appsettings.json b/examples/401-evaluation/appsettings.json index 31bed71a6..f40ad6c98 100644 --- a/examples/401-evaluation/appsettings.json +++ b/examples/401-evaluation/appsettings.json @@ -81,7 +81,7 @@ // the requests across replicas and adversely affect the performance of the search service. // // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body - "UseSessionId": false + "UseStickySessions": false }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/extensions/AzureAISearch/AzureAISearch.FunctionalTests/appsettings.json b/extensions/AzureAISearch/AzureAISearch.FunctionalTests/appsettings.json index d61b27fa1..5262d1964 100644 --- a/extensions/AzureAISearch/AzureAISearch.FunctionalTests/appsettings.json +++ b/extensions/AzureAISearch/AzureAISearch.FunctionalTests/appsettings.json @@ -11,7 +11,8 @@ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET. "Auth": "AzureIdentity", "Endpoint": "https://<...>", - "APIKey": "" + "APIKey": "", + "UseStickySessions": true }, "OpenAI": { // Name of the model used to generate text (text completion or chat completion) diff --git a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs index d90f61e89..35878e5f8 100644 --- a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs +++ b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs @@ -43,7 +43,7 @@ public enum AuthTypes /// /// See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body /// - public bool UseSessionId { get; set; } = false; + public bool UseStickySessions { get; set; } = false; public void SetCredential(TokenCredential credential) { diff --git a/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs b/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs index 4e63a624a..10c97827d 100644 --- a/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs +++ b/extensions/AzureAISearch/AzureAISearch/AzureAISearchMemory.cs @@ -34,7 +34,7 @@ public class AzureAISearchMemory : IMemoryDb, IMemoryDbUpsertBatch private readonly ITextEmbeddingGenerator _embeddingGenerator; private readonly ILogger _log; private readonly bool _useHybridSearch; - private readonly bool _useSessionId; + private readonly bool _useStickySessions; /// /// Create a new instance @@ -50,7 +50,7 @@ public AzureAISearchMemory( this._embeddingGenerator = embeddingGenerator; this._log = (loggerFactory ?? DefaultLogger.Factory).CreateLogger(); this._useHybridSearch = config.UseHybridSearch; - this._useSessionId = config.UseSessionId; + this._useStickySessions = config.UseStickySessions; if (string.IsNullOrEmpty(config.Endpoint)) { @@ -192,13 +192,12 @@ await client.IndexDocumentsAsync( FilterMode = VectorFilterMode.PreFilter } }; - this.ApplyCommonSearchOptions(options, withEmbeddings, filters); + options = this.PrepareSearchOptions(options, withEmbeddings, filters, limit); if (limit > 0) { vectorQuery.KNearestNeighborsCount = limit; - options.Size = limit; - this._log.LogDebug("KNearestNeighborsCount and max results: {0}", limit); + this._log.LogDebug("KNearestNeighborsCount: {0}", limit); } Response>? searchResult = null; @@ -246,14 +245,7 @@ public async IAsyncEnumerable GetListAsync( { var client = this.GetSearchClient(index); - SearchOptions options = new(); - this.ApplyCommonSearchOptions(options, withEmbeddings, filters); - - if (limit > 0) - { - options.Size = limit; - this._log.LogDebug("Max results: {0}", limit); - } + SearchOptions options = this.PrepareSearchOptions(null, withEmbeddings, filters, limit); Response>? searchResult = null; try @@ -601,14 +593,20 @@ at Azure.Search.Documents.SearchClient.SearchInternal[T](SearchOptions options, return indexSchema; } - private void ApplyCommonSearchOptions( - SearchOptions options, + private SearchOptions PrepareSearchOptions( + SearchOptions? options, bool withEmbeddings, - ICollection? filters = null) + ICollection? filters = null, + int limit = 1) { + options ??= new SearchOptions(); + + // Define which fields to fetch options.Select.Add(AzureAISearchMemoryRecord.IdField); options.Select.Add(AzureAISearchMemoryRecord.TagsField); options.Select.Add(AzureAISearchMemoryRecord.PayloadField); + + // Embeddings are fetched only when needed, to reduce latency and cost if (withEmbeddings) { options.Select.Add(AzureAISearchMemoryRecord.VectorField); @@ -633,10 +631,19 @@ private void ApplyCommonSearchOptions( // Size = limit // }; - if (this._useSessionId) + if (limit > 0) + { + options.Size = limit; + this._log.LogDebug("Max results: {0}", limit); + } + + // Decide whether to use a sticky session for the current request + if (this._useStickySessions) { options.SessionId = Guid.NewGuid().ToString("N"); } + + return options; } private static double ScoreToCosineSimilarity(double score) diff --git a/service/Service/appsettings.json b/service/Service/appsettings.json index b040adbdd..83f71fcca 100644 --- a/service/Service/appsettings.json +++ b/service/Service/appsettings.json @@ -291,7 +291,7 @@ // the requests across replicas and adversely affect the performance of the search service. // // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body - "UseSessionId": false + "UseStickySessions": false }, "AzureAIDocIntel": { // "APIKey" or "AzureIdentity". diff --git a/service/tests/Core.FunctionalTests/appsettings.json b/service/tests/Core.FunctionalTests/appsettings.json index 2b0e90b31..19a342d60 100644 --- a/service/tests/Core.FunctionalTests/appsettings.json +++ b/service/tests/Core.FunctionalTests/appsettings.json @@ -12,7 +12,8 @@ "Auth": "AzureIdentity", "Endpoint": "https://<...>", "APIKey": "", - "UseHybridSearch": false + "UseHybridSearch": false, + "UseStickySessions": true }, "LlamaSharp": { "TextModel": { diff --git a/tools/InteractiveSetup/Services/AzureAISearch.cs b/tools/InteractiveSetup/Services/AzureAISearch.cs index 92c2bac18..2e929e869 100644 --- a/tools/InteractiveSetup/Services/AzureAISearch.cs +++ b/tools/InteractiveSetup/Services/AzureAISearch.cs @@ -22,7 +22,7 @@ public static void Setup(Context ctx, bool force = false) { "Auth", "ApiKey" }, { "APIKey", "" }, { "UseHybridSearch", false }, - { "UseSessionId", false } + { "UseStickySessions", false } }; } @@ -46,6 +46,6 @@ public static void Setup(Context ctx, bool force = false) AppSettings.Change(x => x.Services[ServiceName]["Endpoint"] = SetupUI.AskOpenQuestion("Azure AI Search ", config["Endpoint"].ToString())); AppSettings.Change(x => x.Services[ServiceName]["UseHybridSearch"] = SetupUI.AskBoolean("Use hybrid search (yes/no)?", (bool)config["UseHybridSearch"])); - AppSettings.Change(x => x.Services[ServiceName]["UseSessionId"] = SetupUI.AskBoolean("Use session ID (yes/no)?", (bool)config["UseSessionId"])); + AppSettings.Change(x => x.Services[ServiceName]["UseStickySessions"] = SetupUI.AskBoolean("Use sticky sessions (yes/no)?", (bool)config["UseStickySessions"])); } } From 96e6c6396899aa77c454cedcb92f45564faf70a0 Mon Sep 17 00:00:00 2001 From: Devis Lucato Date: Tue, 12 Nov 2024 11:14:30 -0800 Subject: [PATCH 4/5] Adjust tests --- .../AzureAISearch.FunctionalTests/DefaultTests.cs | 4 ++-- .../Diagnostics/SensitiveDataLoggerTests.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/AzureAISearch/AzureAISearch.FunctionalTests/DefaultTests.cs b/extensions/AzureAISearch/AzureAISearch.FunctionalTests/DefaultTests.cs index c02bb50b3..3977ceb6d 100644 --- a/extensions/AzureAISearch/AzureAISearch.FunctionalTests/DefaultTests.cs +++ b/extensions/AzureAISearch/AzureAISearch.FunctionalTests/DefaultTests.cs @@ -14,14 +14,14 @@ public class DefaultTests : BaseFunctionalTestCase public DefaultTests(IConfiguration cfg, ITestOutputHelper output) : base(cfg, output) { Assert.False(string.IsNullOrEmpty(this.AzureAiSearchConfig.Endpoint)); - Assert.False(string.IsNullOrEmpty(this.AzureAiSearchConfig.APIKey)); + Assert.False(this.AzureAiSearchConfig.Auth == AzureAISearchConfig.AuthTypes.APIKey && string.IsNullOrEmpty(this.AzureAiSearchConfig.APIKey)); Assert.False(string.IsNullOrEmpty(this.OpenAiConfig.APIKey)); this._memory = new KernelMemoryBuilder() .With(new KernelMemoryConfig { DefaultIndexName = "default4tests" }) .WithSearchClientConfig(new SearchClientConfig { EmptyAnswer = NotFound }) .WithOpenAI(this.OpenAiConfig) - .WithAzureAISearchMemoryDb(this.AzureAiSearchConfig.Endpoint, this.AzureAiSearchConfig.APIKey) + .WithAzureAISearchMemoryDb(this.AzureAiSearchConfig) .Build(); } diff --git a/service/tests/Abstractions.UnitTests/Diagnostics/SensitiveDataLoggerTests.cs b/service/tests/Abstractions.UnitTests/Diagnostics/SensitiveDataLoggerTests.cs index daa78cd1a..7ef6b1bba 100644 --- a/service/tests/Abstractions.UnitTests/Diagnostics/SensitiveDataLoggerTests.cs +++ b/service/tests/Abstractions.UnitTests/Diagnostics/SensitiveDataLoggerTests.cs @@ -10,6 +10,7 @@ public sealed class SensitiveDataLoggerTests : IDisposable private const string DotNetEnvVar = "DOTNET_ENVIRONMENT"; [Fact] + [Trait("Category", "UnitTest")] public void ItIsDisabledByDefault() { // Assert From d83f75cdaac41ffe3b2e2b2385122647e50485ae Mon Sep 17 00:00:00 2001 From: Devis Lucato Date: Tue, 12 Nov 2024 11:21:26 -0800 Subject: [PATCH 5/5] Fix build --- extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs index 35878e5f8..31990811d 100644 --- a/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs +++ b/extensions/AzureAISearch/AzureAISearch/AzureAISearchConfig.cs @@ -41,7 +41,7 @@ public enum AuthTypes /// Be wary that reusing the same replica repeatedly can interfere with the load balancing of /// the requests across replicas and adversely affect the performance of the search service. /// - /// See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body + /// See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body /// public bool UseStickySessions { get; set; } = false;