diff --git a/extensions/SQLServer/SQLServer/DependencyInjection.cs b/extensions/SQLServer/SQLServer/DependencyInjection.cs
index 926b5d7b1..f0843678e 100644
--- a/extensions/SQLServer/SQLServer/DependencyInjection.cs
+++ b/extensions/SQLServer/SQLServer/DependencyInjection.cs
@@ -30,14 +30,20 @@ public static IKernelMemoryBuilder WithSqlServerMemoryDb(
/// Kernel Memory Builder extension method to add SQL Server memory connector.
///
/// KM builder instance
- /// SQL Server connection string
- /// Whether to use native vector search or not
+ /// SQL Server connection string
+ /// Whether to use native vector search or not.
+ /// When is , it is the vector size used by the VECTOR data type.
+ ///
+ /// Currently, the native Vector search is available on Azure SQL Database only.
+ /// See Overview of vectors in the SQL Database Engine for more information about native Vectors support.
+ ///
public static IKernelMemoryBuilder WithSqlServerMemoryDb(
this IKernelMemoryBuilder builder,
- string connString,
- bool useNativeVectorSearch = false)
+ string connectionString,
+ bool useNativeVectorSearch = false,
+ int vectorSize = SqlServerConfig.DefaultVectorSize)
{
- builder.Services.AddSqlServerAsMemoryDb(connString, useNativeVectorSearch);
+ builder.Services.AddSqlServerAsMemoryDb(connectionString, useNativeVectorSearch, vectorSize);
return builder;
}
}
@@ -56,6 +62,8 @@ public static IServiceCollection AddSqlServerAsMemoryDb(
this IServiceCollection services,
SqlServerConfig config)
{
+ config.Validate();
+
return services
.AddSingleton(config)
.AddSingleton();
@@ -65,14 +73,22 @@ public static IServiceCollection AddSqlServerAsMemoryDb(
/// Inject SQL Server as the default implementation of IMemoryDb
///
/// Service collection
- /// SQL Server connection string
- /// Whether to use native vector search or not
+ /// SQL Server connection string
+ /// Whether to use native vector search or not. Currently, the native Vector search is in Early Access Preview (EAP) and is available on Azure SQL Database and Managed Instance only.
+ /// When is , it is the vector size used by the VECTOR SQL Server type.
public static IServiceCollection AddSqlServerAsMemoryDb(
this IServiceCollection services,
- string connString,
- bool useNativeVectorSearch = false)
+ string connectionString,
+ bool useNativeVectorSearch = false,
+ int vectorSize = SqlServerConfig.DefaultVectorSize)
{
- var config = new SqlServerConfig { ConnectionString = connString, UseNativeVectorSearch = useNativeVectorSearch };
+ var config = new SqlServerConfig
+ {
+ ConnectionString = connectionString,
+ UseNativeVectorSearch = useNativeVectorSearch,
+ VectorSize = vectorSize
+ };
+
return services.AddSqlServerAsMemoryDb(config);
}
}
diff --git a/extensions/SQLServer/SQLServer/QueryProviders/VectorQueryProvider.cs b/extensions/SQLServer/SQLServer/QueryProviders/VectorQueryProvider.cs
index 46ee434eb..3523ef8fa 100644
--- a/extensions/SQLServer/SQLServer/QueryProviders/VectorQueryProvider.cs
+++ b/extensions/SQLServer/SQLServer/QueryProviders/VectorQueryProvider.cs
@@ -90,7 +90,7 @@ public string PrepareGetRecordsListQuery(string index,
SqlParameterCollection parameters)
{
var queryColumns = "[key], [payload], [tags]";
- if (withEmbeddings) { queryColumns += ", VECTOR_TO_JSON_ARRAY([embedding]) AS [embedding]"; }
+ if (withEmbeddings) { queryColumns += ", CAST([embedding] AS NVARCHAR(MAX)) AS [embedding]"; }
var sql = $"""
WITH [filters] AS
@@ -126,7 +126,7 @@ public string PrepareGetSimilarRecordsListQuery(string index,
if (withEmbedding)
{
queryColumns += $"," +
- $"VECTOR_TO_JSON_ARRAY({this.GetFullTableName(this._config.MemoryTableName)}.[embedding]) AS [embedding]";
+ $"CAST({this.GetFullTableName(this._config.MemoryTableName)}.[embedding] AS NVARCHAR(MAX)) AS [embedding]";
}
var generatedFilters = this.GenerateFilters(index, parameters, filters);
@@ -134,11 +134,11 @@ public string PrepareGetSimilarRecordsListQuery(string index,
var sql = $"""
SELECT TOP (@limit)
{queryColumns},
- VECTOR_DISTANCE('cosine', JSON_ARRAY_TO_VECTOR(@vector), Embedding) AS [distance]
+ VECTOR_DISTANCE('cosine', CAST(@vector AS VECTOR({this._config.VectorSize})), Embedding) AS [distance]
FROM
{this.GetFullTableName(this._config.MemoryTableName)}
WHERE
- VECTOR_DISTANCE('cosine', JSON_ARRAY_TO_VECTOR(@vector), Embedding) <= @max_distance
+ VECTOR_DISTANCE('cosine', CAST(@vector AS VECTOR({this._config.VectorSize})), Embedding) <= @max_distance
{generatedFilters}
ORDER BY [distance] ASC
""";
@@ -156,10 +156,10 @@ public string PrepareUpsertRecordsBatchQuery(string index)
USING (SELECT @key) as [src]([key])
ON {this.GetFullTableName(this._config.MemoryTableName)}.[key] = [src].[key]
WHEN MATCHED THEN
- UPDATE SET payload=@payload, embedding=JSON_ARRAY_TO_VECTOR(@embedding), tags=@tags
+ UPDATE SET payload=@payload, embedding=CAST(@embedding AS VECTOR({this._config.VectorSize})), tags=@tags
WHEN NOT MATCHED THEN
- INSERT ([id], [key], [collection], [payload], [tags], [embedding])
- VALUES (NEWID(), @key, @index, @payload, @tags, JSON_ARRAY_TO_VECTOR(@embedding));
+ INSERT ([key], [collection], [payload], [tags], [embedding])
+ VALUES (@key, @index, @payload, @tags, CAST(@embedding AS VECTOR({this._config.VectorSize})));
DELETE FROM [tgt]
FROM {this.GetFullTableName($"{this._config.TagsTableName}_{index}")} AS [tgt]
@@ -211,12 +211,12 @@ PRIMARY KEY ([id])
IF OBJECT_ID(N'{this.GetFullTableName(this._config.MemoryTableName)}', N'U') IS NULL
CREATE TABLE {this.GetFullTableName(this._config.MemoryTableName)}
- ( [id] UNIQUEIDENTIFIER NOT NULL,
+ ( [id] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
[key] NVARCHAR(256) NOT NULL,
[collection] NVARCHAR(256) NOT NULL,
[payload] NVARCHAR(MAX),
[tags] NVARCHAR(MAX),
- [embedding] VARBINARY(8000),
+ [embedding] VECTOR({this._config.VectorSize}),
PRIMARY KEY ([id]),
FOREIGN KEY ([collection]) REFERENCES {this.GetFullTableName(this._config.MemoryCollectionTableName)}([id]) ON DELETE CASCADE,
CONSTRAINT UK_{this._config.MemoryTableName} UNIQUE([collection], [key])
diff --git a/extensions/SQLServer/SQLServer/SqlServerConfig.cs b/extensions/SQLServer/SQLServer/SqlServerConfig.cs
index fca14fe0c..b66af7d2d 100644
--- a/extensions/SQLServer/SQLServer/SqlServerConfig.cs
+++ b/extensions/SQLServer/SQLServer/SqlServerConfig.cs
@@ -30,7 +30,12 @@ public class SqlServerConfig
///
/// The default schema used by the SQL Server memory store.
///
- public const string DefaultSchema = "dbo";
+ internal const string DefaultSchema = "dbo";
+
+ ///
+ /// The default vector size when using the native VECTOR type.
+ ///
+ internal const int DefaultVectorSize = 1536;
///
/// The connection string to the SQL Server database.
@@ -66,8 +71,38 @@ public class SqlServerConfig
/// Whether to use native vector search or not.
///
///
- /// Currently, Vector Search supports only Azure SQL Database and can handle vectors up to 1998 dimensions.
- /// See https://devblogs.microsoft.com/azure-sql/announcing-eap-native-vector-support-in-azure-sql-database for more information.
+ /// Currently, the native Vector search is available on Azure SQL Database only.
+ /// See Overview of vectors in the SQL Database Engine for more information.
///
+ ///
public bool UseNativeVectorSearch { get; set; } = false;
+
+ ///
+ /// The vector size when using the native vector search.
+ ///
+ ///
+ /// Currently, the maximum supported vector size is 1998.
+ /// See Overview of vectors in the SQL Database Engine for more information.
+ ///
+ ///
+ public int VectorSize { get; set; } = DefaultVectorSize;
+
+ ///
+ /// Verify that the current state is valid.
+ ///
+ public void Validate()
+ {
+ if (this.UseNativeVectorSearch)
+ {
+ if (this.VectorSize < 0)
+ {
+ throw new ConfigurationException("The vector size must be greater than 0");
+ }
+
+ if (this.VectorSize > 1998)
+ {
+ throw new ConfigurationException("The vector size must be less than or equal to 1998");
+ }
+ }
+ }
}
diff --git a/extensions/SQLServer/SQLServer/SqlServerMemory.cs b/extensions/SQLServer/SQLServer/SqlServerMemory.cs
index 80300a16c..f00a60c97 100644
--- a/extensions/SQLServer/SQLServer/SqlServerMemory.cs
+++ b/extensions/SQLServer/SQLServer/SqlServerMemory.cs
@@ -290,7 +290,7 @@ public async IAsyncEnumerable GetListAsync(
command.Parameters.AddWithValue("@min_relevance_score", minRelevance);
command.Parameters.AddWithValue("@max_distance", 1 - minRelevance);
- command.Parameters.AddWithValue("@vector", JsonSerializer.Serialize(embedding.Data.ToArray()));
+ command.Parameters.AddWithValue("@vector", JsonSerializer.Serialize(embedding.Data));
command.Parameters.AddWithValue("@index", index);
command.Parameters.AddWithValue("@limit", limit);
@@ -326,7 +326,7 @@ public async Task UpsertAsync(string index, MemoryRecord record, Cancell
{
if (!this._isReady) { await this.InitAsync(cancellationToken).ConfigureAwait(false); }
- await foreach (var item in this.UpsertBatchAsync(index, new[] { record }, cancellationToken).ConfigureAwait(false))
+ await foreach (var item in this.UpsertBatchAsync(index, [record], cancellationToken).ConfigureAwait(false))
{
return item;
}
@@ -363,7 +363,7 @@ public async IAsyncEnumerable UpsertBatchAsync(string index, IEnumerable
command.Parameters.AddWithValue("@key", record.Id);
command.Parameters.AddWithValue("@payload", JsonSerializer.Serialize(record.Payload) ?? (object)DBNull.Value);
command.Parameters.AddWithValue("@tags", JsonSerializer.Serialize(record.Tags) ?? (object)DBNull.Value);
- command.Parameters.AddWithValue("@embedding", JsonSerializer.Serialize(record.Vector.Data.ToArray()));
+ command.Parameters.AddWithValue("@embedding", JsonSerializer.Serialize(record.Vector.Data));
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
command.Dispose();
diff --git a/service/Service/appsettings.json b/service/Service/appsettings.json
index d132ed4b6..49da0a3fb 100644
--- a/service/Service/appsettings.json
+++ b/service/Service/appsettings.json
@@ -633,8 +633,9 @@
"MemoryTableName": "KMMemories",
"EmbeddingsTableName": "KMEmbeddings",
"TagsTableName": "KMMemoriesTags",
- // See https://devblogs.microsoft.com/azure-sql/announcing-eap-native-vector-support-in-azure-sql-database
- "UseNativeVectorSearch": false
+ // See https://learn.microsoft.com/sql/relational-databases/vectors/vectors-sql-server?view=azuresqldb-current
+ "UseNativeVectorSearch": false,
+ "VectorSize": 1536
}
}
}