diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index 290c5501bc07..b2a97f798413 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -59,6 +59,7 @@
+
diff --git a/dotnet/samples/Concepts/Concepts.csproj b/dotnet/samples/Concepts/Concepts.csproj
index 0a8add50d2d2..31d6a392de0e 100644
--- a/dotnet/samples/Concepts/Concepts.csproj
+++ b/dotnet/samples/Concepts/Concepts.csproj
@@ -14,6 +14,7 @@
+
@@ -22,6 +23,7 @@
+
diff --git a/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStore.cs b/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStore.cs
index 6848b38af48f..4fd62592adf3 100644
--- a/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStore.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStore.cs
@@ -40,6 +40,16 @@ public IVectorStoreRecordCollection GetCollection(
return embeddingStore;
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ ArgumentNullException.ThrowIfNull(serviceType);
+
+ return
+ serviceKey is null && serviceType.IsInstanceOfType(this) ? this :
+ this._decoratedVectorStore.GetService(serviceType, serviceKey);
+ }
+
///
public IAsyncEnumerable ListCollectionNamesAsync(CancellationToken cancellationToken = default)
{
diff --git a/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStoreRecordCollection.cs b/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStoreRecordCollection.cs
index 000cb1ebba07..7ac4352e401f 100644
--- a/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStoreRecordCollection.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStoreRecordCollection.cs
@@ -47,6 +47,7 @@ public TextEmbeddingVectorStoreRecordCollection(IVectorStoreRecordCollection
+ [Obsolete("Use GetService(typeof(VectorStoreRecordCollectionMetadata)) to get an information about vector store record collection.")]
public string CollectionName => this._decoratedVectorStoreRecordCollection.CollectionName;
///
@@ -132,6 +133,16 @@ public async Task> VectorizableTextSearchAsync(stri
return await this.VectorizedSearchAsync(embeddingValue, options, cancellationToken).ConfigureAwait(false);
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ ArgumentNullException.ThrowIfNull(serviceType);
+
+ return
+ serviceKey is null && serviceType.IsInstanceOfType(this) ? this :
+ this._decoratedVectorStoreRecordCollection.GetService(serviceType, serviceKey);
+ }
+
///
/// Generate and add embeddings for each embedding field that has a on the provided record.
///
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_Telemetry.cs b/dotnet/samples/Concepts/Memory/VectorStore_Telemetry.cs
index 2165c96aabb2..ae72fd36c9d7 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_Telemetry.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_Telemetry.cs
@@ -1,12 +1,17 @@
// Copyright (c) Microsoft. All rights reserved.
+using System.Diagnostics;
using Azure.Identity;
+using Azure.Monitor.OpenTelemetry.Exporter;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Microsoft.SemanticKernel.Connectors.InMemory;
using Microsoft.SemanticKernel.Embeddings;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
namespace Memory;
@@ -14,8 +19,13 @@ namespace Memory;
/// A simple example showing how to ingest data into a vector store and then use vector search to find related records to a given string
/// with enabled telemetry.
///
-public class VectorStore_Telemetry(ITestOutputHelper output) : BaseTest(output)
+public class VectorStore_Telemetry(ITestOutputHelper output) : BaseTest(output, redirectSystemConsoleOutput: true)
{
+ ///
+ /// Instance of for the example's main activity.
+ ///
+ private static readonly ActivitySource s_activitySource = new("VectorStoreTelemetry.Example");
+
[Fact]
public async Task LoggingManualRegistrationAsync()
{
@@ -91,6 +101,143 @@ public async Task LoggingDependencyInjectionAsync()
// Result: Application Programming Interface. A set of rules and specifications that allow software components to communicate and exchange data.
}
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task TracingAsync(bool useApplicationInsights)
+ {
+ // Create an embedding generation service.
+ var textEmbeddingGenerationService = new AzureOpenAITextEmbeddingGenerationService(
+ TestConfiguration.AzureOpenAIEmbeddings.DeploymentName,
+ TestConfiguration.AzureOpenAIEmbeddings.Endpoint,
+ new AzureCliCredential());
+
+ // Manually construct an InMemory vector store with enabled OpenTelemetry.
+ var vectorStore = new InMemoryVectorStore()
+ .AsBuilder()
+ .UseOpenTelemetry()
+ .Build();
+
+ using var tracerProvider = GetTracerProvider(useApplicationInsights);
+
+ using var activity = s_activitySource.StartActivity("MainActivity");
+ Console.WriteLine($"Operation/Trace ID: {Activity.Current?.TraceId}");
+
+ await RunExampleAsync(textEmbeddingGenerationService, vectorStore);
+
+ // Output:
+ // Activity.DisplayName: create_collection_if_not_exists skglossary
+ // Activity.Duration: 00:00:00.0026442
+ // Activity.Tags:
+ // db.operation.name: create_collection_if_not_exists
+ // db.collection.name: skglossary
+ // db.system.name: inmemory
+ // Activity.DisplayName: upsert skglossary
+ // Activity.Duration: 00:00:00.0010686
+ // Activity.Tags:
+ // db.operation.name: upsert
+ // db.collection.name: skglossary
+ // db.system.name: inmemory
+ // and more...
+
+ // Search string: What is an Application Programming Interface
+ // Result: Application Programming Interface. A set of rules and specifications that allow software components to communicate and exchange data.
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task MeteringAsync(bool useApplicationInsights)
+ {
+ // Create an embedding generation service.
+ var textEmbeddingGenerationService = new AzureOpenAITextEmbeddingGenerationService(
+ TestConfiguration.AzureOpenAIEmbeddings.DeploymentName,
+ TestConfiguration.AzureOpenAIEmbeddings.Endpoint,
+ new AzureCliCredential());
+
+ // Manually construct an InMemory vector store with enabled OpenTelemetry.
+ var vectorStore = new InMemoryVectorStore()
+ .AsBuilder()
+ .UseOpenTelemetry()
+ .Build();
+
+ using var meterProvider = GetMeterProvider(useApplicationInsights);
+
+ await RunExampleAsync(textEmbeddingGenerationService, vectorStore);
+
+ // Output:
+ // Metric Name: db.client.operation.duration, Duration of database client operations., Unit: s, Meter: Experimental.Microsoft.Extensions.VectorData
+
+ // (2025-03-25T20:03:17.9938116Z, 2025-03-25T20:03:20.2214978Z] db.collection.name: skglossary db.operation.name: create_collection_if_not_exists db.system.name: inmemory Histogram
+ // Value: Sum: 0.0015761 Count: 1 Min: 0.0015761 Max: 0.0015761
+
+ // (2025-03-25T20:03:17.9938116Z, 2025-03-25T20:03:20.2214978Z] db.collection.name: skglossary db.operation.name: upsert db.system.name: inmemory Histogram
+ // Value: Sum: 0.0011708 Count: 3 Min: 7E-06 Max: 0.0009944
+
+ // (2025-03-25T20:03:17.9938116Z, 2025-03-25T20:03:20.2214978Z] db.collection.name: skglossary db.operation.name: vectorized_search db.system.name: inmemory Histogram
+ // Value: Sum: 0.0109487 Count: 1 Min: 0.0109487 Max: 0.0109487
+
+ // Search string: What is an Application Programming Interface
+ // Result: Application Programming Interface. A set of rules and specifications that allow software components to communicate and exchange data.
+ }
+
+ #region private
+
+ private TracerProvider? GetTracerProvider(bool useApplicationInsights)
+ {
+ var tracerProviderBuilder = OpenTelemetry.Sdk.CreateTracerProviderBuilder()
+ .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Vector Data Tracing Example"))
+ .AddSource("Experimental.Microsoft.Extensions.VectorData*")
+ .AddSource(s_activitySource.Name);
+
+ if (useApplicationInsights)
+ {
+ var connectionString = TestConfiguration.ApplicationInsights.ConnectionString;
+
+ if (string.IsNullOrWhiteSpace(connectionString))
+ {
+ throw new ConfigurationNotFoundException(
+ nameof(TestConfiguration.ApplicationInsights),
+ nameof(TestConfiguration.ApplicationInsights.ConnectionString));
+ }
+
+ tracerProviderBuilder.AddAzureMonitorTraceExporter(o => o.ConnectionString = connectionString);
+ }
+ else
+ {
+ tracerProviderBuilder.AddConsoleExporter();
+ }
+
+ return tracerProviderBuilder.Build();
+ }
+
+ private MeterProvider? GetMeterProvider(bool useApplicationInsights)
+ {
+ var meterProviderBuilder = OpenTelemetry.Sdk.CreateMeterProviderBuilder()
+ .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Vector Data Metering Example"))
+ .AddMeter("Experimental.Microsoft.Extensions.VectorData*");
+
+ if (useApplicationInsights)
+ {
+ var connectionString = TestConfiguration.ApplicationInsights.ConnectionString;
+
+ if (string.IsNullOrWhiteSpace(connectionString))
+ {
+ throw new ConfigurationNotFoundException(
+ nameof(TestConfiguration.ApplicationInsights),
+ nameof(TestConfiguration.ApplicationInsights.ConnectionString));
+ }
+
+ meterProviderBuilder.AddAzureMonitorMetricExporter(o => o.ConnectionString = connectionString);
+ }
+ else
+ {
+ meterProviderBuilder.AddConsoleExporter();
+ }
+
+ return meterProviderBuilder.Build();
+ }
+
private async Task RunExampleAsync(
ITextEmbeddingGenerationService textEmbeddingGenerationService,
IVectorStore vectorStore)
@@ -177,4 +324,6 @@ private static IEnumerable CreateGlossaryEntries()
Definition = "Retrieval Augmented Generation - a term that refers to the process of retrieving additional data to provide as context to an LLM to use when generating a response (completion) to a user’s question (prompt)."
};
}
+
+ #endregion
}
diff --git a/dotnet/samples/Concepts/Search/VectorStore_TextSearch.cs b/dotnet/samples/Concepts/Search/VectorStore_TextSearch.cs
index f6a3d4ab6356..c9cf9e4310ed 100644
--- a/dotnet/samples/Concepts/Search/VectorStore_TextSearch.cs
+++ b/dotnet/samples/Concepts/Search/VectorStore_TextSearch.cs
@@ -150,6 +150,16 @@ public async Task> VectorizableTextSearchAsync(stri
return await vectorizedSearch.VectorizedSearchAsync(vectorizedQuery, options, cancellationToken);
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ ArgumentNullException.ThrowIfNull(serviceType);
+
+ return
+ serviceKey is null && serviceType.IsInstanceOfType(this) ? this :
+ vectorizedSearch.GetService(serviceType, serviceKey);
+ }
}
///
diff --git a/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreRecordCollectionTests.cs b/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreRecordCollectionTests.cs
index b786c8d8fa58..a9c787aeacdf 100644
--- a/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreRecordCollectionTests.cs
+++ b/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreRecordCollectionTests.cs
@@ -41,6 +41,7 @@ public AzureAISearchVectorStoreRecordCollectionTests()
this._searchClientMock = new Mock(MockBehavior.Strict);
this._searchIndexClientMock = new Mock(MockBehavior.Strict);
this._searchIndexClientMock.Setup(x => x.GetSearchClient(TestCollectionName)).Returns(this._searchClientMock.Object);
+ this._searchIndexClientMock.Setup(x => x.ServiceName).Returns("TestService");
}
[Theory]
diff --git a/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreTests.cs b/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreTests.cs
index b79b048a5f38..f4eed15172fb 100644
--- a/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreTests.cs
+++ b/dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreTests.cs
@@ -32,6 +32,7 @@ public AzureAISearchVectorStoreTests()
this._searchClientMock = new Mock(MockBehavior.Strict);
this._searchIndexClientMock = new Mock(MockBehavior.Strict);
this._searchIndexClientMock.Setup(x => x.GetSearchClient(TestCollectionName)).Returns(this._searchClientMock.Object);
+ this._searchIndexClientMock.Setup(x => x.ServiceName).Returns("TestService");
}
[Fact]
diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStore.cs
index 5329cdf3cee4..f863bb8340c3 100644
--- a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStore.cs
@@ -11,6 +11,8 @@
namespace Microsoft.SemanticKernel.Connectors.AzureAISearch;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Azure AI Search vector store.
///
@@ -19,8 +21,8 @@ namespace Microsoft.SemanticKernel.Connectors.AzureAISearch;
///
public class AzureAISearchVectorStore : IVectorStore
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "AzureAISearch";
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
/// Azure AI Search client that can be used to manage the list of indices in an Azure AI Search Service.
private readonly SearchIndexClient _searchIndexClient;
@@ -39,6 +41,12 @@ public AzureAISearchVectorStore(SearchIndexClient searchIndexClient, AzureAISear
this._searchIndexClient = searchIndexClient;
this._options = options ?? new AzureAISearchVectorStoreOptions();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "azure.aisearch",
+ DatabaseName = searchIndexClient.ServiceName
+ };
}
///
@@ -75,22 +83,38 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
var indexNamesEnumerable = this._searchIndexClient.GetIndexNamesAsync(cancellationToken).ConfigureAwait(false);
var indexNamesEnumerator = indexNamesEnumerable.GetAsyncEnumerator();
- var nextResult = await GetNextIndexNameAsync(indexNamesEnumerator).ConfigureAwait(false);
+ var nextResult = await GetNextIndexNameAsync(indexNamesEnumerator, this._metadata.VectorStoreSystemName).ConfigureAwait(false);
while (nextResult.more)
{
yield return nextResult.name;
- nextResult = await GetNextIndexNameAsync(indexNamesEnumerator).ConfigureAwait(false);
+ nextResult = await GetNextIndexNameAsync(indexNamesEnumerator, this._metadata.VectorStoreSystemName).ConfigureAwait(false);
}
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(SearchIndexClient) ? this._searchIndexClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
///
/// Helper method to get the next index name from the enumerator with a try catch around the move next call to convert
/// any to , since try catch is not supported
/// around a yield return.
///
/// The enumerator to get the next result from.
+ /// The vector store system name.
/// A value indicating whether there are more results and the current string if true.
- private static async Task<(string name, bool more)> GetNextIndexNameAsync(ConfiguredCancelableAsyncEnumerable.Enumerator enumerator)
+ private static async Task<(string name, bool more)> GetNextIndexNameAsync(
+ ConfiguredCancelableAsyncEnumerable.Enumerator enumerator,
+ string? vectorStoreSystemName)
{
const string OperationName = "GetIndexNames";
@@ -103,7 +127,7 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = vectorStoreSystemName,
OperationName = OperationName
};
}
@@ -111,7 +135,7 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = vectorStoreSystemName,
OperationName = OperationName
};
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStoreRecordCollection.cs
index eda71258ef24..e7dd228b2446 100644
--- a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStoreRecordCollection.cs
@@ -18,6 +18,8 @@
namespace Microsoft.SemanticKernel.Connectors.AzureAISearch;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Azure AI Search as the underlying storage.
///
@@ -29,8 +31,8 @@ public class AzureAISearchVectorStoreRecordCollection :
IKeywordHybridSearch
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "AzureAISearch";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// A set of types that a key on the provided model may have.
private static readonly HashSet s_supportedKeyTypes =
@@ -141,6 +143,13 @@ public AzureAISearchVectorStoreRecordCollection(SearchIndexClient searchIndexCli
{
this._mapper = new AzureAISearchGenericDataModelMapper(this._propertyReader.RecordDefinition) as IVectorStoreRecordMapper;
}
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "azure.aisearch",
+ DatabaseName = searchIndexClient.ServiceName,
+ CollectionName = collectionName
+ };
}
///
@@ -162,8 +171,8 @@ public virtual async Task CollectionExistsAsync(CancellationToken cancella
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
- CollectionName = this._collectionName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
+ CollectionName = this._collectionMetadata.CollectionName,
OperationName = "GetIndex"
};
}
@@ -488,6 +497,20 @@ public Task> HybridSearchAsync(TVector vec
return this.SearchAndMapToDataModelAsync(keywordsCombined, searchOptions, internalOptions.IncludeVectors, cancellationToken);
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(SearchIndexClient) ? this._searchIndexClient :
+ serviceType == typeof(SearchClient) ? this._searchClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
///
/// Get the document with the given key and map it to the data model using the configured mapper type.
///
@@ -517,7 +540,7 @@ public Task> HybridSearchAsync(TVector vec
}
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
OperationName,
() => this._mapper!.MapFromStorageToDataModel(jsonObject, new() { IncludeVectors = includeVectors }));
@@ -580,7 +603,7 @@ private Task> MapToStorageModelAndUploadDocumentA
if (this._mapper is not null)
{
var jsonObjects = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
OperationName,
() => records.Select(this._mapper!.MapFromDataToStorageModel));
@@ -608,7 +631,7 @@ private async IAsyncEnumerable> MapSearchResultsAsyn
await foreach (var result in results.ConfigureAwait(false))
{
var document = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
operationName,
() => this._options.JsonObjectCustomMapper!.MapFromStorageToDataModel(result.Document, new() { IncludeVectors = includeVectors }));
@@ -688,8 +711,8 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
- CollectionName = this._collectionName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
+ CollectionName = this._collectionMetadata.CollectionName,
OperationName = operationName
};
}
@@ -697,8 +720,8 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
- CollectionName = this._collectionName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
+ CollectionName = this._collectionMetadata.CollectionName,
OperationName = operationName
};
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStore.cs
index 76dc9e8500a4..7d86b598da80 100644
--- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStore.cs
@@ -9,6 +9,8 @@
namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBMongoDB;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Azure CosmosDB MongoDB vector store.
///
@@ -17,6 +19,9 @@ namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBMongoDB;
///
public class AzureCosmosDBMongoDBVectorStore : IVectorStore
{
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
/// that can be used to manage the collections in Azure CosmosDB MongoDB.
private readonly IMongoDatabase _mongoDatabase;
@@ -34,6 +39,12 @@ public AzureCosmosDBMongoDBVectorStore(IMongoDatabase mongoDatabase, AzureCosmos
this._mongoDatabase = mongoDatabase;
this._options = options ?? new();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "azure.cosmosdbmongodb",
+ DatabaseName = mongoDatabase.DatabaseNamespace?.DatabaseName
+ };
}
///
@@ -75,4 +86,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
}
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(IMongoDatabase) ? this._mongoDatabase :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStoreRecordCollection.cs
index 13e31475447d..5ec62d911a1e 100644
--- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStoreRecordCollection.cs
@@ -17,6 +17,8 @@
namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBMongoDB;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Azure CosmosDB MongoDB as the underlying storage.
///
@@ -25,8 +27,8 @@ namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBMongoDB;
public class AzureCosmosDBMongoDBVectorStoreRecordCollection : IVectorStoreRecordCollection
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "AzureCosmosDBMongoDB";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// Property name to be used for search similarity score value.
private const string ScorePropertyName = "similarityScore";
@@ -93,6 +95,13 @@ public AzureCosmosDBMongoDBVectorStoreRecordCollection(
this._vectorStoragePropertyNames = this._propertyReader.VectorProperties.Select(property => this._storagePropertyNames[property.DataModelPropertyName]).ToList();
this._mapper = this.InitializeMapper();
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "azure.cosmosdbmongodb",
+ DatabaseName = mongoDatabase.DatabaseNamespace?.DatabaseName,
+ CollectionName = collectionName
+ };
}
///
@@ -108,8 +117,8 @@ public virtual async Task CreateCollectionAsync(CancellationToken cancellationTo
{
throw new VectorStoreOperationException("Collection already exists.")
{
- VectorStoreType = DatabaseName,
- CollectionName = this.CollectionName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
+ CollectionName = this._collectionMetadata.CollectionName,
OperationName = "CreateCollection"
};
}
@@ -173,7 +182,7 @@ public virtual Task DeleteCollectionAsync(CancellationToken cancellationToken =
}
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(record, new() { IncludeVectors = includeVectors }));
@@ -200,7 +209,7 @@ public virtual async IAsyncEnumerable GetBatchAsync(
if (record is not null)
{
yield return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(record, new()));
@@ -218,7 +227,7 @@ public virtual Task UpsertAsync(TRecord record, CancellationToken cancel
var replaceOptions = new ReplaceOptions { IsUpsert = true };
var storageModel = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -324,6 +333,20 @@ public virtual async Task> VectorizedSearchAsync(this.EnumerateAndMapSearchResultsAsync(cursor, searchOptions, cancellationToken));
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(IMongoDatabase) ? this._mongoDatabase :
+ serviceType == typeof(IMongoCollection) ? this._mongoCollection :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
#region private
private async Task CreateIndexesAsync(string collectionName, CancellationToken cancellationToken)
@@ -399,7 +422,7 @@ private async IAsyncEnumerable> EnumerateAndMapSearc
{
var score = response[ScorePropertyName].AsDouble;
var record = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(response[DocumentPropertyName].AsBsonDocument, new()));
@@ -438,7 +461,7 @@ private async Task RunOperationAsync(string operationName, Func operation)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -455,7 +478,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStore.cs
index 39320e0a8ae2..6127b3936ea6 100644
--- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStore.cs
@@ -9,6 +9,8 @@
namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBNoSQL;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Azure CosmosDB NoSQL vector store.
///
@@ -17,6 +19,9 @@ namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBNoSQL;
///
public class AzureCosmosDBNoSQLVectorStore : IVectorStore
{
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
/// that can be used to manage the collections in Azure CosmosDB NoSQL.
private readonly Database _database;
@@ -34,6 +39,12 @@ public AzureCosmosDBNoSQLVectorStore(Database database, AzureCosmosDBNoSQLVector
this._database = database;
this._options = options ?? new();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "azure.cosmosdbnosql",
+ DatabaseName = database.Id
+ };
}
///
@@ -84,4 +95,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
}
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(Database) ? this._database :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStoreRecordCollection.cs
index dd0e245c8004..2bb3775852f5 100644
--- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStoreRecordCollection.cs
@@ -17,6 +17,8 @@
namespace Microsoft.SemanticKernel.Connectors.AzureCosmosDBNoSQL;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Azure CosmosDB NoSQL as the underlying storage.
///
@@ -28,8 +30,8 @@ public class AzureCosmosDBNoSQLVectorStoreRecordCollection :
IKeywordHybridSearch
#pragma warning restore CA1711 // Identifiers should not have incorrect
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "AzureCosmosDBNoSQL";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// A of types that a key on the provided model may have.
private static readonly HashSet s_supportedKeyTypes =
@@ -164,6 +166,13 @@ public AzureCosmosDBNoSQLVectorStoreRecordCollection(
.Concat([this._propertyReader.KeyProperty])
.Select(x => this._storagePropertyNames[x.DataModelPropertyName])
.ToList();
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "azure.cosmosdbnosql",
+ DatabaseName = database.Id,
+ CollectionName = collectionName
+ };
}
///
@@ -442,6 +451,19 @@ public Task> HybridSearchAsync(TVector vec
#endregion
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(Database) ? this._database :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
#region private
private void VerifyVectorType(TVector? vector)
@@ -468,7 +490,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -655,7 +677,7 @@ private async IAsyncEnumerable InternalGetAsync(
await foreach (var jsonObject in this.GetItemsAsync(queryDefinition, cancellationToken).ConfigureAwait(false))
{
yield return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(jsonObject, new() { IncludeVectors = includeVectors }));
@@ -671,7 +693,7 @@ private async Task InternalUpsertAsync(
const string OperationName = "UpsertItem";
var jsonObject = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -751,7 +773,7 @@ private async IAsyncEnumerable> MapSearchResultsAsyn
jsonObject.Remove(scorePropertyName);
var record = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
operationName,
() => this._mapper.MapFromStorageToDataModel(jsonObject, new() { IncludeVectors = includeVectors }));
diff --git a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStore.cs
index 2db7013b0d27..c974b6aa5809 100644
--- a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStore.cs
@@ -9,11 +9,16 @@
namespace Microsoft.SemanticKernel.Connectors.InMemory;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Service for storing and retrieving vector records, and managing vector record collections, that uses an in memory dictionary as the underlying storage.
///
public sealed class InMemoryVectorStore : IVectorStore
{
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
/// Internal storage for the record collection.
private readonly ConcurrentDictionary> _internalCollection;
@@ -26,6 +31,11 @@ public sealed class InMemoryVectorStore : IVectorStore
public InMemoryVectorStore()
{
this._internalCollection = new();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "inmemory"
+ };
}
///
@@ -35,6 +45,11 @@ public InMemoryVectorStore()
internal InMemoryVectorStore(ConcurrentDictionary> internalCollection)
{
this._internalCollection = internalCollection;
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "inmemory"
+ };
}
///
@@ -59,4 +74,17 @@ public IAsyncEnumerable ListCollectionNamesAsync(CancellationToken cance
{
return this._internalCollection.Keys.ToAsyncEnumerable();
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(ConcurrentDictionary>) ? this._internalCollection :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStoreRecordCollection.cs
index 6fbcdf2633bf..1effc75a45a0 100644
--- a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStoreRecordCollection.cs
@@ -12,6 +12,8 @@
namespace Microsoft.SemanticKernel.Connectors.InMemory;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses an in memory dictionary as the underlying storage.
///
@@ -22,6 +24,9 @@ public sealed class InMemoryVectorStoreRecordCollection : IVector
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
where TKey : notnull
{
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
+
/// A set of types that vectors on the provided model may have.
private static readonly HashSet s_supportedVectorTypes =
[
@@ -81,6 +86,12 @@ public InMemoryVectorStoreRecordCollection(string collectionName, InMemoryVector
// Assign resolvers.
this._vectorResolver = CreateVectorResolver(this._options.VectorResolver, this._vectorProperties);
this._keyResolver = CreateKeyResolver(this._options.KeyResolver, this._propertyReader.KeyProperty);
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "inmemory",
+ CollectionName = collectionName
+ };
}
///
@@ -278,6 +289,19 @@ public async Task> VectorizedSearchAsync(T
return new VectorSearchResults(vectorSearchResultList) { TotalCount = count };
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(ConcurrentDictionary>) ? this._internalCollections :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
///
/// Get the collection dictionary from the internal storage, throws if it does not exist.
///
diff --git a/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStore.cs
index 27169e3e9557..ee2699e9a3fb 100644
--- a/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStore.cs
@@ -9,6 +9,8 @@
namespace Microsoft.SemanticKernel.Connectors.MongoDB;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a MongoDB vector store.
///
@@ -17,6 +19,9 @@ namespace Microsoft.SemanticKernel.Connectors.MongoDB;
///
public class MongoDBVectorStore : IVectorStore
{
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
/// that can be used to manage the collections in MongoDB.
private readonly IMongoDatabase _mongoDatabase;
@@ -34,6 +39,12 @@ public MongoDBVectorStore(IMongoDatabase mongoDatabase, MongoDBVectorStoreOption
this._mongoDatabase = mongoDatabase;
this._options = options ?? new();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "mongodb",
+ DatabaseName = mongoDatabase.DatabaseNamespace?.DatabaseName
+ };
}
///
@@ -75,4 +86,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
}
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(IMongoDatabase) ? this._mongoDatabase :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStoreRecordCollection.cs
index dc2aa163a803..b5c7c6822abb 100644
--- a/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStoreRecordCollection.cs
@@ -16,6 +16,8 @@
namespace Microsoft.SemanticKernel.Connectors.MongoDB;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses MongoDB as the underlying storage.
///
@@ -24,8 +26,8 @@ namespace Microsoft.SemanticKernel.Connectors.MongoDB;
public class MongoDBVectorStoreRecordCollection : IVectorStoreRecordCollection, IKeywordHybridSearch
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "MongoDB";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// Property name to be used for search similarity score value.
private const string ScorePropertyName = "similarityScore";
@@ -95,6 +97,13 @@ public MongoDBVectorStoreRecordCollection(
this._vectorStoragePropertyNames = this._propertyReader.VectorProperties.Select(property => this._storagePropertyNames[property.DataModelPropertyName]).ToList();
this._mapper = this.InitializeMapper();
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "mongodb",
+ DatabaseName = mongoDatabase.DatabaseNamespace?.DatabaseName,
+ CollectionName = collectionName
+ };
}
///
@@ -110,7 +119,7 @@ public virtual async Task CreateCollectionAsync(CancellationToken cancellationTo
{
throw new VectorStoreOperationException("Collection already exists.")
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = "CreateCollection"
};
@@ -181,7 +190,7 @@ public virtual Task DeleteCollectionAsync(CancellationToken cancellationToken =
}
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(record, new() { IncludeVectors = includeVectors }));
@@ -208,7 +217,7 @@ public virtual async IAsyncEnumerable GetBatchAsync(
if (record is not null)
{
yield return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(record, new()));
@@ -226,7 +235,7 @@ public virtual Task UpsertAsync(TRecord record, CancellationToken cancel
var replaceOptions = new ReplaceOptions { IsUpsert = true };
var storageModel = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -373,6 +382,20 @@ public async Task> HybridSearchAsync(TVect
cancellationToken).ConfigureAwait(false);
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(IMongoDatabase) ? this._mongoDatabase :
+ serviceType == typeof(IMongoCollection) ? this._mongoCollection :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
#region private
private async Task CreateIndexesAsync(string collectionName, CancellationToken cancellationToken)
@@ -490,7 +513,7 @@ private async IAsyncEnumerable> EnumerateAndMapSearc
{
var score = response[ScorePropertyName].AsDouble;
var record = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(response[DocumentPropertyName].AsBsonDocument, new() { IncludeVectors = includeVectors }));
@@ -529,7 +552,7 @@ private async Task RunOperationAsync(string operationName, Func operation)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -546,7 +569,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -577,7 +600,7 @@ private async Task RunOperationWithRetryAsync(
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -611,7 +634,7 @@ private async Task RunOperationWithRetryAsync(
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStore.cs
index a072ea6e7336..138fe7b61947 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStore.cs
@@ -10,6 +10,8 @@
namespace Microsoft.SemanticKernel.Connectors.Pinecone;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Pinecone vector store.
///
@@ -18,11 +20,14 @@ namespace Microsoft.SemanticKernel.Connectors.Pinecone;
///
public class PineconeVectorStore : IVectorStore
{
- private const string DatabaseName = "Pinecone";
+ private const string ListCollectionsName = "ListCollections";
private readonly Sdk.PineconeClient _pineconeClient;
private readonly PineconeVectorStoreOptions _options;
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
///
/// Initializes a new instance of the class.
///
@@ -34,6 +39,11 @@ public PineconeVectorStore(Sdk.PineconeClient pineconeClient, PineconeVectorStor
this._pineconeClient = pineconeClient;
this._options = options ?? new PineconeVectorStoreOptions();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "pinecone"
+ };
}
///
@@ -71,8 +81,8 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
- OperationName = "ListCollections"
+ VectorStoreType = this._metadata.VectorStoreSystemName,
+ OperationName = ListCollectionsName
};
}
@@ -84,4 +94,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
}
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(Sdk.PineconeClient) ? this._pineconeClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStoreRecordCollection.cs
index 3da753575141..92816386cdfc 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStoreRecordCollection.cs
@@ -13,6 +13,8 @@
namespace Microsoft.SemanticKernel.Connectors.Pinecone;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Pinecone as the underlying storage.
///
@@ -21,10 +23,11 @@ namespace Microsoft.SemanticKernel.Connectors.Pinecone;
public class PineconeVectorStoreRecordCollection : IVectorStoreRecordCollection
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- private const string DatabaseName = "Pinecone";
-
private static readonly VectorSearchOptions s_defaultVectorSearchOptions = new();
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
+
private readonly Sdk.PineconeClient _pineconeClient;
private readonly PineconeVectorStoreRecordCollectionOptions _options;
private readonly VectorStoreRecordPropertyReader _propertyReader;
@@ -78,6 +81,12 @@ public PineconeVectorStoreRecordCollection(Sdk.PineconeClient pineconeClient, st
// Default Mapper.
this._mapper = new PineconeVectorStoreRecordMapper(this._propertyReader);
}
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "pinecone",
+ CollectionName = collectionName
+ };
}
///
@@ -153,7 +162,7 @@ public virtual async Task DeleteCollectionAsync(CancellationToken cancellationTo
{
throw new VectorStoreOperationException("Call to vector store failed.", other)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = "DeleteCollection"
};
@@ -183,7 +192,7 @@ public virtual async Task DeleteCollectionAsync(CancellationToken cancellationTo
StorageToDataModelMapperOptions mapperOptions = new() { IncludeVectors = options?.IncludeVectors is true };
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
"Get",
() => this._mapper.MapFromStorageToDataModel(result, mapperOptions));
@@ -219,7 +228,7 @@ public virtual async IAsyncEnumerable GetBatchAsync(
StorageToDataModelMapperOptions mapperOptions = new() { IncludeVectors = options?.IncludeVectors is true };
var records = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
"GetBatch",
() => response.Vectors.Values.Select(x => this._mapper.MapFromStorageToDataModel(x, mapperOptions)));
@@ -274,7 +283,7 @@ public virtual async Task UpsertAsync(TRecord record, CancellationToken
Verify.NotNull(record);
var vector = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
"Upsert",
() => this._mapper.MapFromDataToStorageModel(record));
@@ -298,7 +307,7 @@ public virtual async IAsyncEnumerable UpsertBatchAsync(IEnumerable records.Select(this._mapper.MapFromDataToStorageModel).ToList());
@@ -372,7 +381,7 @@ public virtual async Task> VectorizedSearchAsync skippedResults.Select(x => new VectorSearchResult(this._mapper.MapFromStorageToDataModel(new Sdk.Vector()
@@ -387,6 +396,19 @@ public virtual async Task> VectorizedSearchAsync
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(Sdk.PineconeClient) ? this._pineconeClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
private async Task RunIndexOperationAsync(string operationName, Func> operation)
{
try
@@ -405,7 +427,7 @@ private async Task RunIndexOperationAsync(string operationName, Func RunCollectionOperationAsync(string operationName, Func<
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/IPostgresVectorStoreDbClient.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/IPostgresVectorStoreDbClient.cs
index 020aa46dbda6..9bb3d7e617d1 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Postgres/IPostgresVectorStoreDbClient.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/IPostgresVectorStoreDbClient.cs
@@ -21,6 +21,11 @@ internal interface IPostgresVectorStoreDbClient
///
NpgsqlDataSource DataSource { get; }
+ ///
+ /// The name of the database.
+ ///
+ string? DatabaseName { get; }
+
///
/// Check if a table exists.
///
diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresConstants.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresConstants.cs
index f8784890e83a..ef2491a13b48 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresConstants.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresConstants.cs
@@ -8,9 +8,6 @@ namespace Microsoft.SemanticKernel.Connectors.Postgres;
internal static class PostgresConstants
{
- /// The name of this database for telemetry purposes.
- public const string DatabaseName = "Postgres";
-
/// A of types that a key on the provided model may have.
public static readonly HashSet SupportedKeyTypes =
[
diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStore.cs
index 0f61e692ae7f..2f067ca132a5 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStore.cs
@@ -8,6 +8,8 @@
namespace Microsoft.SemanticKernel.Connectors.Postgres;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Represents a vector store implementation using PostgreSQL.
///
@@ -17,6 +19,9 @@ public class PostgresVectorStore : IVectorStore
private readonly NpgsqlDataSource? _dataSource;
private readonly PostgresVectorStoreOptions _options;
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
///
/// Initializes a new instance of the class.
///
@@ -27,6 +32,12 @@ public PostgresVectorStore(NpgsqlDataSource dataSource, PostgresVectorStoreOptio
this._dataSource = dataSource;
this._options = options ?? new PostgresVectorStoreOptions();
this._postgresClient = new PostgresVectorStoreDbClient(this._dataSource, this._options.Schema);
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "postgresql",
+ DatabaseName = this._postgresClient.DatabaseName
+ };
}
///
@@ -38,6 +49,12 @@ internal PostgresVectorStore(IPostgresVectorStoreDbClient postgresDbClient, Post
{
this._postgresClient = postgresDbClient;
this._options = options ?? new PostgresVectorStoreOptions();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "postgresql",
+ DatabaseName = this._postgresClient.DatabaseName
+ };
}
///
@@ -46,7 +63,8 @@ public virtual IAsyncEnumerable ListCollectionNamesAsync(CancellationTok
const string OperationName = "ListCollectionNames";
return PostgresVectorStoreUtils.WrapAsyncEnumerableAsync(
this._postgresClient.GetTablesAsync(cancellationToken),
- OperationName
+ OperationName,
+ vectorStoreSystemName: this._metadata.VectorStoreSystemName
);
}
@@ -74,4 +92,17 @@ public virtual IVectorStoreRecordCollection GetCollection ?? throw new InvalidOperationException("Failed to cast record collection.");
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(NpgsqlDataSource) ? this._dataSource :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreDbClient.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreDbClient.cs
index a167aad9cd02..9938a910b269 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreDbClient.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreDbClient.cs
@@ -26,10 +26,14 @@ internal class PostgresVectorStoreDbClient(NpgsqlDataSource dataSource, string s
{
private readonly string _schema = schema;
+ private readonly NpgsqlConnectionStringBuilder _connectionStringBuilder = new(dataSource.ConnectionString);
+
private IPostgresVectorStoreCollectionSqlBuilder _sqlBuilder = new PostgresVectorStoreCollectionSqlBuilder();
public NpgsqlDataSource DataSource { get; } = dataSource;
+ public string? DatabaseName => this._connectionStringBuilder.Database;
+
///
public async Task DoesTableExistsAsync(string tableName, CancellationToken cancellationToken = default)
{
diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreRecordCollection.cs
index ce619398bf99..f8a6523b5833 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreRecordCollection.cs
@@ -11,6 +11,8 @@
namespace Microsoft.SemanticKernel.Connectors.Postgres;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Represents a collection of vector store records in a Postgres database.
///
@@ -24,6 +26,9 @@ public class PostgresVectorStoreRecordCollection : IVectorStoreRe
///
public string CollectionName { get; }
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
+
/// Postgres client that is used to interact with the database.
private readonly IPostgresVectorStoreDbClient _client;
@@ -102,6 +107,13 @@ internal PostgresVectorStoreRecordCollection(IPostgresVectorStoreDbClient client
{
this._mapper = new PostgresVectorStoreRecordMapper(this._propertyReader);
}
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "postgresql",
+ DatabaseName = this._client.DatabaseName,
+ CollectionName = collectionName
+ };
}
///
@@ -146,7 +158,7 @@ public virtual Task UpsertAsync(TRecord record, CancellationToken cancella
const string OperationName = "Upsert";
var storageModel = VectorStoreErrorHandler.RunModelConversion(
- PostgresConstants.DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -173,7 +185,7 @@ public virtual async IAsyncEnumerable UpsertBatchAsync(IEnumerable VectorStoreErrorHandler.RunModelConversion(
- PostgresConstants.DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record))).ToList();
@@ -207,7 +219,7 @@ await this.RunOperationAsync(OperationName, () =>
if (row is null) { return default; }
return VectorStoreErrorHandler.RunModelConversion(
- PostgresConstants.DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(row, new() { IncludeVectors = includeVectors }));
@@ -227,14 +239,15 @@ public virtual IAsyncEnumerable GetBatchAsync(IEnumerable keys, G
this._client.GetBatchAsync(this.CollectionName, keys, this._propertyReader.RecordDefinition.Properties, includeVectors, cancellationToken)
.SelectAsync(row =>
VectorStoreErrorHandler.RunModelConversion(
- PostgresConstants.DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(row, new() { IncludeVectors = includeVectors })),
cancellationToken
),
OperationName,
- this.CollectionName
+ this.CollectionName,
+ this._collectionMetadata.VectorStoreSystemName
);
}
@@ -303,7 +316,7 @@ public virtual Task> VectorizedSearchAsync
.SelectAsync(result =>
{
var record = VectorStoreErrorHandler.RunModelConversion(
- PostgresConstants.DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(
@@ -317,6 +330,19 @@ public virtual Task> VectorizedSearchAsync
});
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(NpgsqlDataSource) ? this._client.DataSource :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
private Task InternalCreateCollectionAsync(bool ifNotExists, CancellationToken cancellationToken = default)
{
return this._client.CreateTableAsync(this.CollectionName, this._propertyReader.RecordDefinition.Properties, ifNotExists, cancellationToken);
@@ -332,7 +358,7 @@ private async Task RunOperationAsync(string operationName, Func operation)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = PostgresConstants.DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -349,7 +375,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = PostgresConstants.DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreUtils.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreUtils.cs
index 27fa7181bdc5..ef4e78cf9237 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreUtils.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreUtils.cs
@@ -18,16 +18,21 @@ internal static class PostgresVectorStoreUtils
/// The async enumerable to wrap.
/// The name of the operation being performed.
/// The name of the collection being operated on.
+ /// The name of the vector store system being operated on.
/// An async enumerable that will throw a if an exception is thrown while iterating over the original enumerator.
- public static async IAsyncEnumerable WrapAsyncEnumerableAsync(IAsyncEnumerable asyncEnumerable, string operationName, string? collectionName = null)
+ public static async IAsyncEnumerable WrapAsyncEnumerableAsync(
+ IAsyncEnumerable asyncEnumerable,
+ string operationName,
+ string? collectionName = null,
+ string? vectorStoreSystemName = null)
{
var enumerator = asyncEnumerable.ConfigureAwait(false).GetAsyncEnumerator();
- var nextResult = await GetNextAsync(enumerator, operationName, collectionName).ConfigureAwait(false);
+ var nextResult = await GetNextAsync(enumerator, operationName, collectionName, vectorStoreSystemName).ConfigureAwait(false);
while (nextResult.more)
{
yield return nextResult.item;
- nextResult = await GetNextAsync(enumerator, operationName, collectionName).ConfigureAwait(false);
+ nextResult = await GetNextAsync(enumerator, operationName, collectionName, vectorStoreSystemName).ConfigureAwait(false);
}
}
@@ -38,8 +43,13 @@ public static async IAsyncEnumerable WrapAsyncEnumerableAsync(IAsyncEnumer
/// The enumerator to get the next result from.
/// The name of the operation being performed.
/// The name of the collection being operated on.
+ /// The name of the vector store system being operated on.
/// A value indicating whether there are more results and the current string if true.
- public static async Task<(T item, bool more)> GetNextAsync(ConfiguredCancelableAsyncEnumerable.Enumerator enumerator, string operationName, string? collectionName = null)
+ public static async Task<(T item, bool more)> GetNextAsync(
+ ConfiguredCancelableAsyncEnumerable.Enumerator enumerator,
+ string operationName,
+ string? collectionName = null,
+ string? vectorStoreSystemName = null)
{
try
{
@@ -50,7 +60,7 @@ public static async IAsyncEnumerable WrapAsyncEnumerableAsync(IAsyncEnumer
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = PostgresConstants.DatabaseName,
+ VectorStoreType = vectorStoreSystemName,
CollectionName = collectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStore.cs
index bfac788a7cfd..051956ba964f 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStore.cs
@@ -10,6 +10,8 @@
namespace Microsoft.SemanticKernel.Connectors.Qdrant;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Qdrant vector store.
///
@@ -18,8 +20,8 @@ namespace Microsoft.SemanticKernel.Connectors.Qdrant;
///
public class QdrantVectorStore : IVectorStore
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "Qdrant";
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
/// Qdrant client that can be used to manage the collections and points in a Qdrant store.
private readonly MockableQdrantClient _qdrantClient;
@@ -48,6 +50,11 @@ internal QdrantVectorStore(MockableQdrantClient qdrantClient, QdrantVectorStoreO
this._qdrantClient = qdrantClient;
this._options = options ?? new QdrantVectorStoreOptions();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "qdrant"
+ };
}
///
@@ -88,7 +95,7 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._metadata.VectorStoreSystemName,
OperationName = "ListCollections"
};
}
@@ -98,4 +105,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
yield return collection;
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(QdrantClient) ? this._qdrantClient.QdrantClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStoreRecordCollection.cs
index 760aeaae24f4..3217e6fa16cf 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStoreRecordCollection.cs
@@ -14,6 +14,8 @@
namespace Microsoft.SemanticKernel.Connectors.Qdrant;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Qdrant as the underlying storage.
///
@@ -25,6 +27,9 @@ public class QdrantVectorStoreRecordCollection :
IKeywordHybridSearch
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
+
/// A set of types that a key on the provided model may have.
private static readonly HashSet s_supportedKeyTypes =
[
@@ -38,9 +43,6 @@ public class QdrantVectorStoreRecordCollection :
/// The default options for hybrid vector search.
private static readonly HybridSearchOptions s_defaultKeywordVectorizedHybridSearchOptions = new();
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "Qdrant";
-
/// The name of the upsert operation for telemetry purposes.
private const string UpsertName = "Upsert";
@@ -128,6 +130,12 @@ internal QdrantVectorStoreRecordCollection(MockableQdrantClient qdrantClient, st
this._propertyReader,
this._options.HasNamedVectors);
}
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "qdrant",
+ CollectionName = collectionName
+ };
}
///
@@ -352,7 +360,7 @@ public virtual async Task UpsertAsync(TRecord record, CancellationToken c
// Create point from record.
var pointStruct = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
UpsertName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -371,7 +379,7 @@ async Task IVectorStoreRecordCollection.UpsertAsync(TRecord
// Create point from record.
var pointStruct = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
UpsertName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -390,7 +398,7 @@ public virtual async IAsyncEnumerable UpsertBatchAsync(IEnumerable records.Select(this._mapper.MapFromDataToStorageModel).ToList());
@@ -413,7 +421,7 @@ async IAsyncEnumerable IVectorStoreRecordCollection.UpsertB
// Create points from records.
var pointStructs = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
UpsertName,
() => records.Select(this._mapper.MapFromDataToStorageModel).ToList());
@@ -471,7 +479,7 @@ private async IAsyncEnumerable GetBatchByPointIdAsync(
}
yield return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(pointStruct, new() { IncludeVectors = includeVectors }));
@@ -532,7 +540,7 @@ public virtual async Task> VectorizedSearchAsync> HybridSearchAsync(TVect
point,
this._mapper,
internalOptions.IncludeVectors,
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
"Query"));
return new VectorSearchResults(mappedResults.ToAsyncEnumerable());
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(QdrantClient) ? this._qdrantClient.QdrantClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
///
/// Run the given operation and wrap any with ."/>
///
@@ -647,7 +668,7 @@ private async Task RunOperationAsync(string operationName, Func operation)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = operationName
};
@@ -671,7 +692,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisHashSetVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisHashSetVectorStoreRecordCollection.cs
index a08fe1e86628..a682c84d615e 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisHashSetVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisHashSetVectorStoreRecordCollection.cs
@@ -14,6 +14,8 @@
namespace Microsoft.SemanticKernel.Connectors.Redis;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Redis HashSets as the underlying storage.
///
@@ -22,8 +24,8 @@ namespace Microsoft.SemanticKernel.Connectors.Redis;
public class RedisHashSetVectorStoreRecordCollection : IVectorStoreRecordCollection
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "Redis";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// A set of types that a key on the provided model may have.
private static readonly HashSet s_supportedKeyTypes =
@@ -141,6 +143,13 @@ public RedisHashSetVectorStoreRecordCollection(IDatabase database, string collec
// Default Mapper.
this._mapper = new RedisHashSetVectorStoreRecordMapper(this._propertyReader);
}
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "redis",
+ DatabaseName = database.Database.ToString(),
+ CollectionName = collectionName
+ };
}
///
@@ -162,7 +171,7 @@ public virtual async Task CollectionExistsAsync(CancellationToken cancella
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = "FT.INFO"
};
@@ -251,7 +260,7 @@ await this.RunOperationAsync("FT.DROPINDEX",
// Convert to the caller's data model.
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
operationName,
() =>
@@ -309,7 +318,7 @@ public virtual async Task UpsertAsync(TRecord record, CancellationToken
// Map.
var redisHashSetRecord = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
"HSET",
() => this._mapper.MapFromDataToStorageModel(record));
@@ -377,7 +386,7 @@ public virtual async Task> VectorizedSearchAsync
@@ -396,6 +405,19 @@ public virtual async Task> VectorizedSearchAsync(mappedResults.ToAsyncEnumerable());
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(IDatabase) ? this._database :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
///
/// Prefix the key with the collection name if the option is set.
///
@@ -445,7 +467,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = operationName
};
@@ -468,7 +490,7 @@ private async Task RunOperationAsync(string operationName, Func operation)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisJsonVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisJsonVectorStoreRecordCollection.cs
index af6a0a7d220f..6fa422fce726 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisJsonVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisJsonVectorStoreRecordCollection.cs
@@ -17,6 +17,8 @@
namespace Microsoft.SemanticKernel.Connectors.Redis;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Redis JSON as the underlying storage.
///
@@ -25,8 +27,8 @@ namespace Microsoft.SemanticKernel.Connectors.Redis;
public class RedisJsonVectorStoreRecordCollection : IVectorStoreRecordCollection
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "Redis";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// A set of types that a key on the provided model may have.
private static readonly HashSet s_supportedKeyTypes =
@@ -123,6 +125,13 @@ public RedisJsonVectorStoreRecordCollection(IDatabase database, string collectio
// Default Mapper.
this._mapper = new RedisJsonVectorStoreRecordMapper(this._propertyReader.KeyPropertyJsonName, this._jsonSerializerOptions);
}
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "redis",
+ DatabaseName = database.Database.ToString(),
+ CollectionName = collectionName
+ };
}
///
@@ -144,7 +153,7 @@ public virtual async Task CollectionExistsAsync(CancellationToken cancella
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = "FT.INFO"
};
@@ -233,7 +242,7 @@ await this.RunOperationAsync("FT.DROPINDEX",
// Convert to the caller's data model.
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
"GET",
() =>
@@ -282,7 +291,7 @@ public virtual async IAsyncEnumerable GetBatchAsync(IEnumerable
// Convert to the caller's data model.
yield return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
"MGET",
() =>
@@ -326,7 +335,7 @@ public virtual async Task UpsertAsync(TRecord record, CancellationToken
// Map.
var redisJsonRecord = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this._collectionName,
"SET",
() =>
@@ -360,7 +369,7 @@ public virtual async IAsyncEnumerable UpsertBatchAsync(IEnumerable
@@ -416,7 +425,7 @@ public virtual async Task> VectorizedSearchAsync
@@ -438,6 +447,19 @@ public virtual async Task> VectorizedSearchAsync(mappedResults.ToAsyncEnumerable());
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(IDatabase) ? this._database :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
///
/// Prefix the key with the collection name if the option is set.
///
@@ -486,7 +508,7 @@ private async Task RunOperationAsync(string operationName, Func operation)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = operationName
};
@@ -510,7 +532,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this._collectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisVectorStore.cs
index 4966917d3990..2366b889b647 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisVectorStore.cs
@@ -10,6 +10,8 @@
namespace Microsoft.SemanticKernel.Connectors.Redis;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Redis vector store.
///
@@ -18,8 +20,8 @@ namespace Microsoft.SemanticKernel.Connectors.Redis;
///
public class RedisVectorStore : IVectorStore
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "Redis";
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
/// The redis database to read/write indices from.
private readonly IDatabase _database;
@@ -38,6 +40,12 @@ public RedisVectorStore(IDatabase database, RedisVectorStoreOptions? options = d
this._database = database;
this._options = options ?? new RedisVectorStoreOptions();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "redis",
+ DatabaseName = database.Database.ToString()
+ };
}
///
@@ -82,7 +90,7 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._metadata.VectorStoreSystemName,
OperationName = OperationName
};
}
@@ -96,4 +104,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
}
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(IDatabase) ? this._metadata :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStore.cs
index d9481ffc467d..4c686b8305fb 100644
--- a/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStore.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
+using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -8,6 +9,8 @@
namespace Microsoft.SemanticKernel.Connectors.SqlServer;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// An implementation of backed by a SQL Server or Azure SQL database.
///
@@ -16,6 +19,9 @@ public sealed class SqlServerVectorStore : IVectorStore
private readonly string _connectionString;
private readonly SqlServerVectorStoreOptions _options;
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
///
/// Initializes a new instance of the class.
///
@@ -31,6 +37,14 @@ public SqlServerVectorStore(string connectionString, SqlServerVectorStoreOptions
this._options = options is not null
? new() { Schema = options.Schema }
: SqlServerVectorStoreOptions.Defaults;
+
+ var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "microsoft.sql_server",
+ DatabaseName = connectionStringBuilder.InitialCatalog
+ };
}
///
@@ -63,4 +77,16 @@ public async IAsyncEnumerable ListCollectionNamesAsync([EnumeratorCancel
yield return reader.GetString(reader.GetOrdinal("table_name"));
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStoreRecordCollection.cs
index 9b4ce3b29078..7e11cc02f37f 100644
--- a/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.SqlServer/SqlServerVectorStoreRecordCollection.cs
@@ -11,6 +11,8 @@
namespace Microsoft.SemanticKernel.Connectors.SqlServer;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// An implementation of backed by a SQL Server or Azure SQL database.
///
@@ -19,6 +21,9 @@ public sealed class SqlServerVectorStoreRecordCollection
#pragma warning restore CA1711
: IVectorStoreRecordCollection where TKey : notnull
{
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
+
private static readonly VectorSearchOptions s_defaultVectorSearchOptions = new();
private static readonly SqlServerVectorStoreRecordCollectionOptions s_defaultOptions = new();
@@ -88,6 +93,15 @@ public SqlServerVectorStoreRecordCollection(
this._mapper = new RecordMapper(propertyReader);
}
+
+ var connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "microsoft.sql_server",
+ DatabaseName = connectionStringBuilder.InitialCatalog,
+ CollectionName = name
+ };
}
///
@@ -474,6 +488,18 @@ public async Task> VectorizedSearchAsync(T
}, cancellationToken, "VectorizedSearch", this.CollectionName).ConfigureAwait(false);
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
private async IAsyncEnumerable> ReadVectorSearchResultsAsync(
SqlConnection connection,
SqlCommand command,
diff --git a/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStore.cs
index f5b9615884ff..a126a290fc8a 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStore.cs
@@ -10,6 +10,8 @@
namespace Microsoft.SemanticKernel.Connectors.Sqlite;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a SQLite vector store.
///
@@ -18,6 +20,9 @@ namespace Microsoft.SemanticKernel.Connectors.Sqlite;
///
public class SqliteVectorStore : IVectorStore
{
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
/// The connection string for the SQLite database represented by this .
private readonly string _connectionString;
@@ -35,6 +40,14 @@ public SqliteVectorStore(string connectionString, SqliteVectorStoreOptions? opti
this._connectionString = connectionString;
this._options = options ?? new();
+
+ var connectionStringBuilder = new SqliteConnectionStringBuilder(connectionString);
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "sqlite",
+ DatabaseName = connectionStringBuilder.DataSource
+ };
}
///
@@ -100,4 +113,16 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
yield return reader.GetString(ordinal);
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStoreRecordCollection.cs
index 16dbd7238aca..53eec93755b1 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteVectorStoreRecordCollection.cs
@@ -12,6 +12,8 @@
namespace Microsoft.SemanticKernel.Connectors.Sqlite;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses SQLite as the underlying storage.
///
@@ -22,8 +24,8 @@ public class SqliteVectorStoreRecordCollection :
IVectorStoreRecordCollection
#pragma warning restore CA1711 // Identifiers should not have incorrect
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "SQLite";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// The connection string for the SQLite database represented by this .
private readonly string _connectionString;
@@ -112,6 +114,15 @@ public SqliteVectorStoreRecordCollection(
this._vectorTableStoragePropertyNames = new(() => [this._propertyReader.KeyPropertyStoragePropertyName, .. this._propertyReader.VectorPropertyStoragePropertyNames]);
this._mapper = this.InitializeMapper();
+
+ var connectionStringBuilder = new SqliteConnectionStringBuilder(connectionString);
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "sqlite",
+ DatabaseName = connectionStringBuilder.DataSource,
+ CollectionName = collectionName
+ };
}
///
@@ -338,6 +349,18 @@ public async Task DeleteBatchAsync(IEnumerable keys, CancellationToken c
#endregion
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
#region private
private async ValueTask GetConnectionAsync(CancellationToken cancellationToken = default)
@@ -555,7 +578,7 @@ private async Task InternalUpsertAsync(SqliteConnection connection,
const string OperationName = "Upsert";
var storageModel = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record));
@@ -578,7 +601,7 @@ private IAsyncEnumerable InternalUpsertBatchAsync(SqliteConnection c
const string OperationName = "UpsertBatch";
var storageModels = records.Select(record => VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record))).ToList();
@@ -711,7 +734,7 @@ private TRecord GetAndMapRecord(
}
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
operationName,
() => this._mapper.MapFromStorageToDataModel(storageModel, new() { IncludeVectors = includeVectors }));
@@ -727,7 +750,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStore.cs b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStore.cs
index 1c45d1e3ac65..dfb03bde493f 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStore.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStore.cs
@@ -11,6 +11,8 @@
namespace Microsoft.SemanticKernel.Connectors.Weaviate;
+#pragma warning disable SKEXP0020 // VectorStoreMetadata is experimental
+
///
/// Class for accessing the list of collections in a Weaviate vector store.
///
@@ -19,6 +21,9 @@ namespace Microsoft.SemanticKernel.Connectors.Weaviate;
///
public class WeaviateVectorStore : IVectorStore
{
+ /// Metadata about vector store.
+ private readonly VectorStoreMetadata _metadata;
+
/// that is used to interact with Weaviate API.
private readonly HttpClient _httpClient;
@@ -40,6 +45,11 @@ public WeaviateVectorStore(HttpClient httpClient, WeaviateVectorStoreOptions? op
this._httpClient = httpClient;
this._options = options ?? new();
+
+ this._metadata = new()
+ {
+ VectorStoreSystemName = "weaviate"
+ };
}
///
@@ -92,4 +102,17 @@ public virtual async IAsyncEnumerable ListCollectionNamesAsync([Enumerat
}
}
}
+
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreMetadata) ? this._metadata :
+ serviceType == typeof(HttpClient) ? this._httpClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
}
diff --git a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStoreRecordCollection.cs b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStoreRecordCollection.cs
index 393b9a841cbb..6e488a3c56a7 100644
--- a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStoreRecordCollection.cs
+++ b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateVectorStoreRecordCollection.cs
@@ -16,6 +16,8 @@
namespace Microsoft.SemanticKernel.Connectors.Weaviate;
+#pragma warning disable SKEXP0020 // Metadata classes are experimental
+
///
/// Service for storing and retrieving vector records, that uses Weaviate as the underlying storage.
///
@@ -24,8 +26,8 @@ namespace Microsoft.SemanticKernel.Connectors.Weaviate;
public class WeaviateVectorStoreRecordCollection : IVectorStoreRecordCollection, IKeywordHybridSearch
#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
{
- /// The name of this database for telemetry purposes.
- private const string DatabaseName = "Weaviate";
+ /// Metadata about vector store record collection.
+ private readonly VectorStoreRecordCollectionMetadata _collectionMetadata;
/// A set of types that a key on the provided model may have.
private static readonly HashSet s_supportedKeyTypes =
@@ -154,6 +156,12 @@ public WeaviateVectorStoreRecordCollection(
// Assign mapper.
this._mapper = this.InitializeMapper();
+
+ this._collectionMetadata = new()
+ {
+ VectorStoreSystemName = "weaviate",
+ CollectionName = collectionName
+ };
}
///
@@ -270,7 +278,7 @@ public virtual Task DeleteBatchAsync(IEnumerable keys, CancellationToken c
}
return VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromStorageToDataModel(jsonObject!, new() { IncludeVectors = includeVectors }));
@@ -312,7 +320,7 @@ public virtual async IAsyncEnumerable UpsertBatchAsync(IEnumerable
{
var jsonObjects = records.Select(record => VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
OperationName,
() => this._mapper.MapFromDataToStorageModel(record))).ToList();
@@ -395,6 +403,19 @@ public async Task> HybridSearchAsync(TVect
return await this.ExecuteQueryAsync(query, searchOptions.IncludeVectors, WeaviateConstants.HybridScorePropertyName, OperationName, cancellationToken).ConfigureAwait(false);
}
+ ///
+ public object? GetService(Type serviceType, object? serviceKey = null)
+ {
+ Verify.NotNull(serviceType);
+
+ return
+ serviceKey is not null ? null :
+ serviceType == typeof(VectorStoreRecordCollectionMetadata) ? this._collectionMetadata :
+ serviceType == typeof(HttpClient) ? this._httpClient :
+ serviceType.IsInstanceOfType(this) ? this :
+ null;
+ }
+
#region private
private async Task> ExecuteQueryAsync(string query, bool includeVectors, string scorePropertyName, string operationName, CancellationToken cancellationToken)
@@ -409,7 +430,7 @@ private async Task> ExecuteQueryAsync(string query,
{
throw new VectorStoreOperationException($"Error occurred during vector search. Response: {content}")
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
@@ -420,7 +441,7 @@ private async Task> ExecuteQueryAsync(string query,
var (storageModel, score) = WeaviateVectorStoreCollectionSearchMapping.MapSearchResult(result!, scorePropertyName);
var record = VectorStoreErrorHandler.RunModelConversion(
- DatabaseName,
+ this._collectionMetadata.VectorStoreSystemName!,
this.CollectionName,
operationName,
() => this._mapper.MapFromStorageToDataModel(storageModel, new() { IncludeVectors = includeVectors }));
@@ -483,7 +504,7 @@ private async Task RunOperationAsync(string operationName, Func> o
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
- VectorStoreType = DatabaseName,
+ VectorStoreType = this._collectionMetadata.VectorStoreSystemName,
CollectionName = this.CollectionName,
OperationName = operationName
};
diff --git a/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreRecordCollectionTests.cs b/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreRecordCollectionTests.cs
index 0533ab28c3f3..3493162d5095 100644
--- a/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreRecordCollectionTests.cs
+++ b/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreRecordCollectionTests.cs
@@ -22,6 +22,7 @@ public class PostgresVectorStoreRecordCollectionTests
public PostgresVectorStoreRecordCollectionTests()
{
this._postgresClientMock = new Mock(MockBehavior.Strict);
+ this._postgresClientMock.Setup(l => l.DatabaseName).Returns("TestDatabase");
}
[Fact]
diff --git a/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreTests.cs b/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreTests.cs
index 33cfc005a7bc..8a89582fc0f8 100644
--- a/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreTests.cs
+++ b/dotnet/src/Connectors/Connectors.Postgres.UnitTests/PostgresVectorStoreTests.cs
@@ -26,6 +26,7 @@ public class PostgresVectorStoreTests
public PostgresVectorStoreTests()
{
this._postgresClientMock = new Mock(MockBehavior.Strict);
+ this._postgresClientMock.Setup(l => l.DatabaseName).Returns("TestDatabase");
}
[Fact]
@@ -60,7 +61,10 @@ public void GetCollectionCallsFactoryIfProvided()
var factoryMock = new Mock(MockBehavior.Strict);
var collectionMock = new Mock>>(MockBehavior.Strict);
var clientMock = new Mock(MockBehavior.Strict);
+
clientMock.Setup(x => x.DataSource).Returns(null);
+ clientMock.Setup(x => x.DatabaseName).Returns("TestDatabase");
+
factoryMock
.Setup(x => x.CreateVectorStoreRecordCollection>(It.IsAny(), TestCollectionName, null))
.Returns(collectionMock.Object);
diff --git a/dotnet/src/Connectors/Connectors.Redis.UnitTests/RedisHashSetVectorStoreRecordCollectionTests.cs b/dotnet/src/Connectors/Connectors.Redis.UnitTests/RedisHashSetVectorStoreRecordCollectionTests.cs
index 117d3d1fcd4b..74c3dc49cf28 100644
--- a/dotnet/src/Connectors/Connectors.Redis.UnitTests/RedisHashSetVectorStoreRecordCollectionTests.cs
+++ b/dotnet/src/Connectors/Connectors.Redis.UnitTests/RedisHashSetVectorStoreRecordCollectionTests.cs
@@ -28,6 +28,7 @@ public class RedisHashSetVectorStoreRecordCollectionTests
public RedisHashSetVectorStoreRecordCollectionTests()
{
this._redisDatabaseMock = new Mock(MockBehavior.Strict);
+ this._redisDatabaseMock.Setup(l => l.Database).Returns(0);
var batchMock = new Mock();
this._redisDatabaseMock.Setup(x => x.CreateBatch(It.IsAny