-
Notifications
You must be signed in to change notification settings - Fork 299
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for SQL Server Vector Search (#722)
## Motivation and Context (Why the change? What's the scenario?) Azure SQL Database now provides native Vector Support, currently in EAP (https://devblogs.microsoft.com/azure-sql/announcing-eap-native-vector-support-in-azure-sql-database). This PR extends SQL Server Memory DB with a flag that allows to use this new feature. > [!IMPORTANT] > Remember that, at this time, Vector Support is available only on Azure SQL Database. On the other hand, the current SQL Server Memory DB requires a COLUMNSTORE INDEX that, on Azure, is available only on vCore databases and Standard databases in S3 and above pricing tiers (https://azure.microsoft.com/en-us/blog/columnstore-support-in-standard-tier-azure-sql-databases). --------- Co-authored-by: Devis Lucato <[email protected]>
- Loading branch information
1 parent
4c6c8c7
commit ccfb815
Showing
8 changed files
with
766 additions
and
308 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
319 changes: 319 additions & 0 deletions
319
extensions/SQLServer/SQLServer/QueryProviders/DefaultQueryProvider.cs
Large diffs are not rendered by default.
Oops, something went wrong.
59 changes: 59 additions & 0 deletions
59
extensions/SQLServer/SQLServer/QueryProviders/ISqlServerQueryProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using Microsoft.Data.SqlClient; | ||
|
||
namespace Microsoft.KernelMemory.MemoryDb.SQLServer.QueryProviders; | ||
|
||
public interface ISqlServerQueryProvider | ||
{ | ||
/// <summary> | ||
/// Return SQL used to create a new index | ||
/// </summary> | ||
public string PrepareCreateIndexQuery( | ||
int sqlServerVersion, | ||
string index, | ||
int vectorSize); | ||
|
||
/// <summary> | ||
/// Return SQL used to get a list of indexes | ||
/// </summary> | ||
public string PrepareGetIndexesQuery(); | ||
|
||
/// <summary> | ||
/// Return SQL used to delete an index | ||
/// </summary> | ||
public string PrepareDeleteIndexQuery(string index); | ||
|
||
/// <summary> | ||
/// Return SQL used to delete a memory record | ||
/// </summary> | ||
public string PrepareDeleteRecordQuery(string index); | ||
|
||
/// <summary> | ||
/// Return SQL used to get a list of memory records | ||
/// </summary> | ||
public string PrepareGetRecordsListQuery( | ||
string index, | ||
ICollection<MemoryFilter>? filters, | ||
bool withEmbedding, | ||
SqlParameterCollection parameters); | ||
|
||
/// <summary> | ||
/// Return SQL used to get a list of similar memory records | ||
/// </summary> | ||
public string PrepareGetSimilarRecordsListQuery( | ||
string index, | ||
ICollection<MemoryFilter>? filters, | ||
bool withEmbedding, | ||
SqlParameterCollection parameters); | ||
|
||
/// <summary> | ||
/// Return SQL used to upsert a batch of memory records | ||
/// </summary> | ||
public string PrepareUpsertRecordsBatchQuery(string index); | ||
|
||
/// <summary> | ||
/// Return SQL used to create all supporting tables | ||
/// </summary> | ||
public string PrepareCreateAllSupportingTablesQuery(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System.Globalization; | ||
using System.Text; | ||
using Microsoft.Data.SqlClient; | ||
|
||
namespace Microsoft.KernelMemory.MemoryDb.SQLServer.QueryProviders; | ||
|
||
internal static class Utils | ||
{ | ||
/// <summary> | ||
/// Gets the full table name with schema. | ||
/// </summary> | ||
/// <param name="config">Server settings</param> | ||
/// <param name="tableName">The table name.</param> | ||
internal static string GetFullTableName(SqlServerConfig config, string tableName) | ||
{ | ||
return $"[{config.Schema}].[{tableName}]"; | ||
} | ||
|
||
/// <summary> | ||
/// Generates the filters as SQL commands and sets the SQL parameters | ||
/// </summary> | ||
/// <param name="config">Server settings</param> | ||
/// <param name="index">The index name.</param> | ||
/// <param name="parameters">The SQL parameters to populate.</param> | ||
/// <param name="filters">The filters to apply</param> | ||
internal static string GenerateFilters( | ||
SqlServerConfig config, | ||
string index, | ||
SqlParameterCollection parameters, | ||
ICollection<MemoryFilter>? filters) | ||
{ | ||
var filterBuilder = new StringBuilder(); | ||
|
||
if (filters is null || filters.Count <= 0 || filters.All(f => f.Count <= 0)) | ||
{ | ||
return string.Empty; | ||
} | ||
|
||
filterBuilder.Append("AND ( "); | ||
|
||
for (int i = 0; i < filters.Count; i++) | ||
{ | ||
var filter = filters.ElementAt(i); | ||
|
||
if (i > 0) | ||
{ | ||
filterBuilder.Append(" OR "); | ||
} | ||
|
||
for (int j = 0; j < filter.Pairs.Count(); j++) | ||
{ | ||
var value = filter.Pairs.ElementAt(j); | ||
|
||
if (j > 0) | ||
{ | ||
filterBuilder.Append(" AND "); | ||
} | ||
|
||
filterBuilder.Append(" ( "); | ||
|
||
filterBuilder.Append(CultureInfo.CurrentCulture, $@"EXISTS ( | ||
SELECT | ||
1 | ||
FROM {GetFullTableName(config, $"{config.TagsTableName}_{index}")} AS [tags] | ||
WHERE | ||
[tags].[memory_id] = {GetFullTableName(config, config.MemoryTableName)}.[id] | ||
AND [name] = @filter_{i}_{j}_name | ||
AND [value] = @filter_{i}_{j}_value | ||
) | ||
"); | ||
|
||
filterBuilder.Append(" ) "); | ||
|
||
parameters.AddWithValue($"@filter_{i}_{j}_name", value.Key); | ||
parameters.AddWithValue($"@filter_{i}_{j}_value", value.Value); | ||
} | ||
} | ||
|
||
filterBuilder.Append(" )"); | ||
|
||
return filterBuilder.ToString(); | ||
} | ||
} |
Oops, something went wrong.