Elastic.SemanticKernel.Connectors.Elasticsearch/ElasticsearchVectorStore.cs (70 lines of code) (raw):
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using Elastic.Clients.Elasticsearch;
using Elastic.Transport;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
namespace Elastic.SemanticKernel.Connectors.Elasticsearch;
/// <summary>
/// Class for accessing the list of collections in a Elasticsearch vector store.
/// </summary>
/// <remarks>
/// This class can be used with collections of any schema type, but requires you to provide schema information when
/// getting a collection.
/// </remarks>
public sealed class ElasticsearchVectorStore :
IVectorStore
{
/// <summary>The name of this database for telemetry purposes.</summary>
private const string DatabaseName = "Elasticsearch";
/// <summary>Elasticsearch client that can be used to manage the collections and points in an Elasticsearch store.</summary>
private readonly MockableElasticsearchClient _elasticsearchClient;
/// <summary>Optional configuration options for this class.</summary>
private readonly ElasticsearchVectorStoreOptions _options;
/// <summary>
/// Initializes a new instance of the <see cref="ElasticsearchVectorStore" /> class.
/// </summary>
/// <param name="elasticsearchClient">
/// Elasticsearch client that can be used to manage the collections and points in an
/// Elasticsearch store.
/// </param>
/// <param name="options">Optional configuration options for this class.</param>
public ElasticsearchVectorStore(ElasticsearchClient elasticsearchClient,
ElasticsearchVectorStoreOptions? options = default)
: this(new MockableElasticsearchClient(elasticsearchClient), options)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ElasticsearchVectorStore" /> class.
/// </summary>
/// <param name="elasticsearchClient">
/// Elasticsearch client that can be used to manage the collections and points in an
/// Elasticsearch store.
/// </param>
/// <param name="options">Optional configuration options for this class.</param>
internal ElasticsearchVectorStore(MockableElasticsearchClient elasticsearchClient,
ElasticsearchVectorStoreOptions? options = default)
{
Verify.NotNull(elasticsearchClient);
_elasticsearchClient = elasticsearchClient;
_options = options ?? new ElasticsearchVectorStoreOptions();
}
/// <inheritdoc />
public IVectorStoreRecordCollection<TKey, TRecord> GetCollection<TKey, TRecord>(string name,
VectorStoreRecordDefinition? vectorStoreRecordDefinition = null)
where TKey : notnull
{
if (typeof(TKey) != typeof(string))
{
throw new NotSupportedException("Only string keys are supported.");
}
if (_options.VectorStoreCollectionFactory is not null)
{
return _options.VectorStoreCollectionFactory.CreateVectorStoreRecordCollection<TKey, TRecord>(
_elasticsearchClient.ElasticsearchClient, name, vectorStoreRecordDefinition);
}
var recordCollection = new ElasticsearchVectorStoreRecordCollection<TRecord>(_elasticsearchClient, name,
new ElasticsearchVectorStoreRecordCollectionOptions<TRecord>
{
VectorStoreRecordDefinition = vectorStoreRecordDefinition
});
var castRecordCollection = recordCollection as IVectorStoreRecordCollection<TKey, TRecord>;
return castRecordCollection!;
}
/// <inheritdoc />
public async IAsyncEnumerable<string> ListCollectionNamesAsync(
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
IReadOnlyList<string> collections;
try
{
collections = await _elasticsearchClient.ListIndicesAsync(cancellationToken).ConfigureAwait(false);
}
catch (TransportException ex)
{
throw new VectorStoreOperationException("Call to vector store failed.", ex)
{
VectorStoreType = DatabaseName,
OperationName = "ListCollections"
};
}
foreach (var collection in collections)
{
yield return collection;
}
}
}