diff --git a/Directory.Build.props b/Directory.Build.props index eaa6948..f9e6df2 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,7 +9,7 @@ https://github.com/qdrant/qdrant-dotnet https://github.com/qdrant/qdrant-dotnet/releases qdrant, database, vector, search - v1.17.0 + v1.18.0 @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/build/Build.csproj b/build/Build.csproj index c055f56..8ec2671 100644 --- a/build/Build.csproj +++ b/build/Build.csproj @@ -11,7 +11,7 @@ - + diff --git a/build/Main.cs b/build/Main.cs index a2f473c..59dcc99 100644 --- a/build/Main.cs +++ b/build/Main.cs @@ -1,10 +1,10 @@ using System.CommandLine; using System.CommandLine.Invocation; -using System.IO.Compression; using System.Net.Http.Headers; using System.Text.RegularExpressions; using System.Xml.Linq; using Bullseye; +using SharpCompress.Common; using SharpCompress.Readers; using static BuildTargets; using static Bullseye.Targets; @@ -87,13 +87,12 @@ var response = await client.GetAsync(url); await using var stream = await response.Content.ReadAsStreamAsync(); - await using var gzip = new GZipStream(stream, CompressionMode.Decompress); - var reader = ReaderFactory.Open(gzip); + using var reader = ReaderFactory.OpenReader(stream); while (reader.MoveToNextEntry()) { var entry = reader.Entry; if (!entry.IsDirectory && protoFileRegex.IsMatch(entry.Key!) && !privateProtoFileRegex.IsMatch(entry.Key!)) - reader.WriteEntryToDirectory(protosTagDir); + reader.WriteEntryToDirectory(protosTagDir, new ExtractionOptions { ExtractFullPath = false, Overwrite = true }); } { diff --git a/src/Qdrant.Client/IQdrantClient.cs b/src/Qdrant.Client/IQdrantClient.cs index 25ebd45..38cbbce 100644 --- a/src/Qdrant.Client/IQdrantClient.cs +++ b/src/Qdrant.Client/IQdrantClient.cs @@ -1394,6 +1394,28 @@ Task DeletePayloadIndexAsync( WriteOrderingType? ordering = null, CancellationToken cancellationToken = default); + /// + /// Creates a new named vector on a collection. + /// + /// The create vector name request. + /// + /// The token to monitor for cancellation requests. The default value is . + /// + Task CreateVectorNameAsync( + CreateVectorNameRequest request, + CancellationToken cancellationToken = default); + + /// + /// Deletes a named vector from a collection. + /// + /// The delete vector name request. + /// + /// The token to monitor for cancellation requests. The default value is . + /// + Task DeleteVectorNameAsync( + DeleteVectorNameRequest request, + CancellationToken cancellationToken = default); + /// /// Retrieves closest points based on vector similarity and the given filtering conditions. /// diff --git a/src/Qdrant.Client/LoggingExtensions.cs b/src/Qdrant.Client/LoggingExtensions.cs index a5e9866..caa6d67 100644 --- a/src/Qdrant.Client/LoggingExtensions.cs +++ b/src/Qdrant.Client/LoggingExtensions.cs @@ -80,6 +80,12 @@ internal static partial class LoggingExtensions [LoggerMessage(3014, LogLevel.Debug, "Delete payload field index in '{collection}'")] public static partial void DeletePayloadIndex(this ILogger logger, string collection); + [LoggerMessage(3032, LogLevel.Debug, "Create vector name '{vectorName}' in '{collection}'")] + public static partial void CreateVectorName(this ILogger logger, string collection, string vectorName); + + [LoggerMessage(3033, LogLevel.Debug, "Delete vector name '{vectorName}' in '{collection}'")] + public static partial void DeleteVectorName(this ILogger logger, string collection, string vectorName); + [LoggerMessage(3015, LogLevel.Debug, "Search on '{collection}'")] public static partial void Search(this ILogger logger, string collection); diff --git a/src/Qdrant.Client/QdrantClient.cs b/src/Qdrant.Client/QdrantClient.cs index ea1e419..d9c9dfd 100644 --- a/src/Qdrant.Client/QdrantClient.cs +++ b/src/Qdrant.Client/QdrantClient.cs @@ -1444,8 +1444,6 @@ public async Task UpsertAsync( if (updateFilter is not null) request.UpdateFilter = updateFilter; - _logger.Upsert(collectionName, points.Count); - return await UpsertAsync(request, cancellationToken).ConfigureAwait(false); } @@ -3010,6 +3008,56 @@ public async Task DeletePayloadIndexAsync( } } + /// + public async Task CreateVectorNameAsync( + CreateVectorNameRequest request, + CancellationToken cancellationToken = default) + { + _logger.CreateVectorName(request.CollectionName, request.VectorName); + + try + { + var response = await _pointsClient.CreateVectorNameAsync( + request, + deadline: _grpcTimeout == default ? null : DateTime.UtcNow.Add(_grpcTimeout), + cancellationToken: cancellationToken) + .ConfigureAwait(false); + + return response.Result; + } + catch (Exception e) + { + _logger.OperationFailed(nameof(LoggingExtensions.CreateVectorName), e); + + throw; + } + } + + /// + public async Task DeleteVectorNameAsync( + DeleteVectorNameRequest request, + CancellationToken cancellationToken = default) + { + _logger.DeleteVectorName(request.CollectionName, request.VectorName); + + try + { + var response = await _pointsClient.DeleteVectorNameAsync( + request, + deadline: _grpcTimeout == default ? null : DateTime.UtcNow.Add(_grpcTimeout), + cancellationToken: cancellationToken) + .ConfigureAwait(false); + + return response.Result; + } + catch (Exception e) + { + _logger.OperationFailed(nameof(LoggingExtensions.DeleteVectorName), e); + + throw; + } + } + /// /// Retrieves closest points based on vector similarity and the given filtering conditions. /// diff --git a/tests/Qdrant.Client.Tests/CollectionTests.cs b/tests/Qdrant.Client.Tests/CollectionTests.cs index 1a0c91e..ed66a0e 100644 --- a/tests/Qdrant.Client.Tests/CollectionTests.cs +++ b/tests/Qdrant.Client.Tests/CollectionTests.cs @@ -195,6 +195,41 @@ public async Task DeleteAlias() Assert.Empty(await _client.ListCollectionAliasesAsync("collection_1")); } + [Fact] + public async Task CreateAndDeleteVector() + { + const string collectionName = "collection_1"; + + await _client.CreateCollectionAsync(collectionName, new VectorParamsMap + { + Map = { ["vector_1"] = new() { Size = 4, Distance = Distance.Dot } } + }); + + await _client.CreateVectorNameAsync(new() + { + CollectionName = collectionName, + VectorName = "vector_2", + Wait = true, + DenseConfig = new() { Size = 8, Distance = Distance.Cosine } + }); + + var info = await _client.GetCollectionInfoAsync(collectionName); + var vectors = info.Config.Params.VectorsConfig.ParamsMap.Map; + vectors.Should().HaveCount(2).And.ContainKeys("vector_1", "vector_2"); + + await _client.DeleteVectorNameAsync(new() + { + CollectionName = collectionName, + VectorName = "vector_2", + Wait = true + }); + + info = await _client.GetCollectionInfoAsync(collectionName); + vectors = info.Config.Params.VectorsConfig.ParamsMap.Map; + vectors.Should().HaveCount(1).And.ContainKeys("vector_1"); + } + + public async Task InitializeAsync() { foreach (var collection in await _client.ListCollectionsAsync())