From 802b0c9318624d96d357d94afaa98223389235f4 Mon Sep 17 00:00:00 2001 From: generall Date: Sat, 25 Jul 2026 12:26:42 +0200 Subject: [PATCH 1/3] Update rust client for 1.19 Sync protobuf definitions from qdrant `dev` and expose the new API surface. * Memory placement (`Memory` enum) on vector storage, HNSW graph, sparse index, all quantization configs and all payload index params. Deprecates `on_disk` / `always_ram` in favour of `memory`. * Payload storage params (`PayloadStorageParams`) on `CreateCollection` and `CollectionParamsDiff`. Deprecates `on_disk_payload` in favour of `payload`. * Keyword index prefix matching + `Condition::matches_prefix`. * `Condition::slice` for deterministic id-space slicing. * Per-request IDF corpus (`IdfParams`) on `SearchParams`. * Explicitly disabled stemming for the text index. * `StrictModeConfig::max_disk_usage_percent`. * `Datatype::Turbo4`. Co-Authored-By: Claude Opus 5 (1M context) --- proto/collections.proto | 170 ++++++++++-- proto/points.proto | 14 +- proto/qdrant_common.proto | 10 + src/builders/binary_quantization_builder.rs | 20 ++ src/builders/bool_index_params_builder.rs | 13 + .../collection_params_diff_builder.rs | 16 ++ src/builders/create_collection_builder.rs | 16 ++ src/builders/datetime_index_params_builder.rs | 13 + src/builders/float_index_params_builder.rs | 13 + src/builders/geo_index_params_builder.rs | 13 + src/builders/hnsw_config_diff_builder.rs | 18 ++ src/builders/integer_index_params_builder.rs | 13 + src/builders/keyword_index_params_builder.rs | 23 ++ src/builders/product_quantization_builder.rs | 13 + src/builders/scalar_quantization_builder.rs | 13 + src/builders/search_params_builder.rs | 13 + src/builders/sparse_index_config_builder.rs | 15 ++ src/builders/strict_mode_config_builder.rs | 11 + src/builders/text_index_params_builder.rs | 26 ++ src/builders/turbo_quantization_builder.rs | 14 + src/builders/uuid_index_params_builder.rs | 13 + src/builders/vector_params_builder.rs | 14 + src/builders/vector_params_diff_builder.rs | 14 + src/filters.rs | 52 +++- src/grpc_conversions/mod.rs | 45 +++- src/qdrant.rs | 249 +++++++++++++++++- tests/builder_coverage.rs | 30 ++- tests/snippet_tests/mod.rs | 8 + .../test_create_collection_with_memory.rs | 36 +++ ..._create_collection_with_turbo4_datatype.rs | 23 ++ ...eate_collection_with_turbo_quantization.rs | 4 +- .../test_create_keyword_index_with_prefix.rs | 29 ++ ...test_create_text_index_without_stemming.rs | 33 +++ .../test_query_points_with_idf_corpus.rs | 32 +++ .../test_scroll_points_with_prefix_match.rs | 21 ++ .../test_scroll_points_with_slice.rs | 25 ++ .../test_update_collection_memory.rs | 36 +++ 37 files changed, 1068 insertions(+), 53 deletions(-) create mode 100644 tests/snippet_tests/test_create_collection_with_memory.rs create mode 100644 tests/snippet_tests/test_create_collection_with_turbo4_datatype.rs create mode 100644 tests/snippet_tests/test_create_keyword_index_with_prefix.rs create mode 100644 tests/snippet_tests/test_create_text_index_without_stemming.rs create mode 100644 tests/snippet_tests/test_query_points_with_idf_corpus.rs create mode 100644 tests/snippet_tests/test_scroll_points_with_prefix_match.rs create mode 100644 tests/snippet_tests/test_scroll_points_with_slice.rs create mode 100644 tests/snippet_tests/test_update_collection_memory.rs diff --git a/proto/collections.proto b/proto/collections.proto index 1d52f4cc..fd067ab6 100644 --- a/proto/collections.proto +++ b/proto/collections.proto @@ -11,6 +11,20 @@ enum Datatype { Float32 = 1; Uint8 = 2; Float16 = 3; + Turbo4 = 4; +} + +// Memory placement of a component's data. +// Data is always persisted on disk regardless of this setting; +// it only controls how the data is held in RAM. +enum Memory { + MemoryUnknown = 0; + // Data is not pre-loaded from disk to RAM; cached with usage. + Cold = 1; + // Data is pre-loaded into disk-cache RAM on start, but may be evicted under memory pressure. + Cached = 2; + // Data is loaded in RAM and never evicted. + Pinned = 3; } // --------------------------------------------- @@ -28,13 +42,18 @@ message VectorParams { // Configuration of vector quantization config. // If omitted - the collection configuration will be used optional QuantizationConfig quantization_config = 4; + // Deprecated: use `memory` instead. // If true - serve vectors from disk. // If set to false, the vectors will be loaded in RAM. - optional bool on_disk = 5; + optional bool on_disk = 5 [deprecated = true]; // Data type of the vectors optional Datatype datatype = 6; // Configuration for multi-vector search optional MultiVectorConfig multivector_config = 7; + // Memory placement of the original vector storage. + // Overrides the deprecated `on_disk` flag if both are set. + // `Pinned` is not supported for dense vector storage. + optional Memory memory = 8; } message VectorParamsDiff { @@ -43,9 +62,14 @@ message VectorParamsDiff { optional HnswConfigDiff hnsw_config = 1; // Update quantization params. If none - it is left unchanged. optional QuantizationConfigDiff quantization_config = 2; + // Deprecated: use `memory` instead. // If true - serve vectors from disk. // If set to false, the vectors will be loaded in RAM. - optional bool on_disk = 3; + optional bool on_disk = 3 [deprecated = true]; + // Memory placement of the original vector storage. + // Overrides the deprecated `on_disk` flag if both are set. + // `Pinned` is not supported for dense vector storage. + optional Memory memory = 4; } message VectorParamsMap { @@ -218,8 +242,9 @@ message HnswConfigDiff { // Best to keep between 8 and 16 to prevent likelihood of building broken/inefficient HNSW graphs. // On small CPUs, less threads are used. optional uint64 max_indexing_threads = 4; + // Deprecated: use `memory` instead. // Store HNSW index on disk. If set to false, the index will be stored in RAM. - optional bool on_disk = 5; + optional bool on_disk = 5 [deprecated = true]; // Number of additional payload-aware links per node in the index graph. // If not set - regular M parameter will be used. optional uint64 payload_m = 6; @@ -228,16 +253,23 @@ message HnswConfigDiff { // random seeks during the search. // Requires quantized vectors to be enabled. Multi-vectors are not supported. optional bool inline_storage = 7; + // Memory placement of the HNSW graph. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 8; } message SparseIndexConfig { // Prefer a full scan search upto (excluding) this number of vectors. // Note: this is number of vectors, not KiloBytes. optional uint64 full_scan_threshold = 1; + // Deprecated: use `memory` instead. // Store inverted index on disk. If set to false, the index will be stored in RAM. - optional bool on_disk = 2; + optional bool on_disk = 2 [deprecated = true]; // Datatype used to store weights in the index. optional Datatype datatype = 3; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 4; } message WalConfigDiff { @@ -307,10 +339,14 @@ message OptimizersConfigDiff { // If 0 - no optimization threads, optimizations will be disabled. optional MaxOptimizationThreads max_optimization_threads = 9; - // If this option is set, service will try to prevent creation of large unoptimized segments. - // When enabled, updates may be blocked at request level if there are unoptimized segments larger than indexing threshold. - // Updates will be resumed when optimization is completed and segments are optimized below the threshold. - // Using this option may lead to increased delay between submitting an update and its application. + // If enabled, the service will try to prevent the creation of large unoptimized segments. + // When enabled, new points written to segments larger than the indexing threshold are stored + // as "deferred points": they are persisted in the WAL and segments, but excluded from + // read/search results until the corresponding segments are optimized (e.g. indexed, + // quantized, or moved to mmap storage). + // Update requests with wait=true will only return after the deferred points become visible, + // which may significantly increase the perceived latency between submitting an update and its + // completion. Update requests with wait=false are not affected. // Default is disabled. optional bool prevent_unoptimized = 10; } @@ -320,15 +356,23 @@ message ScalarQuantization { QuantizationType type = 1; // Number of bits to use for quantization optional float quantile = 2; + // Deprecated: use `memory` instead. // If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - optional bool always_ram = 3; + optional bool always_ram = 3 [deprecated = true]; + // Memory placement of quantized vectors. + // Overrides the deprecated `always_ram` flag if both are set. + optional Memory memory = 4; } message ProductQuantization { // Compression ratio CompressionRatio compression = 1; + // Deprecated: use `memory` instead. // If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - optional bool always_ram = 2; + optional bool always_ram = 2 [deprecated = true]; + // Memory placement of quantized vectors. + // Overrides the deprecated `always_ram` flag if both are set. + optional Memory memory = 3; } enum BinaryQuantizationEncoding { @@ -351,19 +395,27 @@ message BinaryQuantizationQueryEncoding { } message BinaryQuantization { + // Deprecated: use `memory` instead. // If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - optional bool always_ram = 1; + optional bool always_ram = 1 [deprecated = true]; // Binary quantization encoding method optional BinaryQuantizationEncoding encoding = 2; // Asymmetric quantization configuration allows a query to have different // quantization than stored vectors. // It can increase the accuracy of search at the cost of performance. optional BinaryQuantizationQueryEncoding query_encoding = 3; + // Memory placement of quantized vectors. + // Overrides the deprecated `always_ram` flag if both are set. + optional Memory memory = 4; } message TurboQuantization{ - optional bool always_ram = 1; + // Deprecated: use `memory` instead. + optional bool always_ram = 1 [deprecated = true]; optional TurboQuantBitSize bits = 2; + // Memory placement of quantized vectors. + // Overrides the deprecated `always_ram` flag if both are set. + optional Memory memory = 3; } enum TurboQuantBitSize{ @@ -445,6 +497,9 @@ message StrictModeConfig { // Reject memory-consuming update operations when process resident memory exceeds this percentage of total RAM (cgroup-aware, 1-100). // Delete-style operations are still allowed so memory can be freed. optional uint32 max_resident_memory_percent = 21; + // Reject disk-consuming update operations when the filesystem hosting Qdrant storage exceeds this percentage of total capacity (1-100). + // Free space is sampled with a small TTL cache so the gate may take a few seconds to react. Delete-style operations are still allowed so disk can be freed. + optional uint32 max_disk_usage_percent = 22; } message StrictModeSparseConfig { @@ -465,6 +520,14 @@ message StrictModeMultivector { optional uint64 max_vectors = 1; } +// Params of the payload storage +message PayloadStorageParams { + // Memory placement of the payload storage. + // Overrides the deprecated `on_disk_payload` flag if both are set. + // `Pinned` is not supported for payload storage. + optional Memory memory = 1; +} + message CreateCollection { // Name of the collection string collection_name = 1; @@ -481,8 +544,9 @@ message CreateCollection { // Number of shards in the collection, default is 1 for standalone, otherwise // equal to the number of nodes. Minimum is 1 optional uint32 shard_number = 7; + // Deprecated: use `payload.memory` instead. // If true - point's payload will not be stored in memory - optional bool on_disk_payload = 8; + optional bool on_disk_payload = 8 [deprecated = true]; // Wait timeout for operation commit in seconds, if not specified - default // value will be supplied optional uint64 timeout = 9; @@ -504,6 +568,8 @@ message CreateCollection { optional StrictModeConfig strict_mode_config = 17; // Arbitrary JSON metadata for the collection map metadata = 18; + // Configuration of the payload storage + optional PayloadStorageParams payload = 19; } message UpdateCollection { @@ -555,8 +621,9 @@ message CollectionParams { reserved 2; // Number of shards in collection uint32 shard_number = 3; + // Deprecated: use `payload.memory` instead. // If true - point's payload will not be stored in memory - bool on_disk_payload = 4; + bool on_disk_payload = 4 [deprecated = true]; // Configuration for vectors optional VectorsConfig vectors_config = 5; // Number of replicas of each shard that network tries to maintain @@ -571,6 +638,8 @@ message CollectionParams { optional SparseVectorConfig sparse_vectors_config = 10; // Define number of milliseconds to wait before attempting to read from another replica. optional uint64 read_fan_out_delay_ms = 11; + // Configuration of the payload storage + optional PayloadStorageParams payload = 12; } message CollectionParamsDiff { @@ -578,12 +647,15 @@ message CollectionParamsDiff { optional uint32 replication_factor = 1; // How many replicas should apply the operation for us to consider it successful optional uint32 write_consistency_factor = 2; + // Deprecated: use `payload.memory` instead. // If true - point's payload will not be stored in memory - optional bool on_disk_payload = 3; + optional bool on_disk_payload = 3 [deprecated = true]; // Fan-out every read request to these many additional remote nodes (and return first available response) optional uint32 read_fan_out_factor = 4; // Define number of milliseconds to wait before attempting to read from another replica. optional uint64 read_fan_out_delay_ms = 5; + // Update params of the payload storage + optional PayloadStorageParams payload = 6; } message CollectionConfig { @@ -614,12 +686,23 @@ enum TokenizerType { message KeywordIndexParams { // If true - used for tenant optimization. optional bool is_tenant = 1; + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 2; + optional bool on_disk = 2 [deprecated = true]; // Enable HNSW graph building for this payload field. // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 3; + // If set, enable prefix matching (`match: { "prefix": ... }`) on this field. + optional KeywordPrefixParams prefix = 4; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 5; +} + +// Prefix matching options for the keyword index. Has no options yet: +// presence of this message enables prefix matching. +message KeywordPrefixParams { } message IntegerIndexParams { @@ -631,17 +714,22 @@ message IntegerIndexParams { // This option assumes that this key will be used in majority of filtered requests. // Default is false. optional bool is_principal = 3; + // Deprecated: use `memory` instead. // If true - store index on disk. Default is false. - optional bool on_disk = 4; + optional bool on_disk = 4 [deprecated = true]; // Enable HNSW graph building for this payload field. // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 5; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 6; } message FloatIndexParams { + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 1; + optional bool on_disk = 1 [deprecated = true]; // If true - use this key to organize storage of the collection data. // This option assumes that this key will be used in majority of filtered requests. optional bool is_principal = 2; @@ -649,15 +737,22 @@ message FloatIndexParams { // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 3; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 4; } message GeoIndexParams { + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 1; + optional bool on_disk = 1 [deprecated = true]; // Enable HNSW graph building for this payload field. // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 2; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 3; } message StopwordsSet { @@ -676,8 +771,9 @@ message TextIndexParams { optional uint64 min_token_len = 3; // Maximal token length optional uint64 max_token_len = 4; + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 5; + optional bool on_disk = 5 [deprecated = true]; // Stopwords for the text index optional StopwordsSet stopwords = 6; // If true - support phrase matching. @@ -691,12 +787,17 @@ message TextIndexParams { // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 10; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 11; } message StemmingAlgorithm { oneof stemming_params { // Parameters for snowball stemming SnowballParams snowball = 1; + // Explicitly disable stemming (overrides the language default) + DisabledStemmer disabled = 2; } } @@ -705,18 +806,26 @@ message SnowballParams { string language = 1; } +// Marker selecting the "no stemming" algorithm. +message DisabledStemmer {} + message BoolIndexParams { + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 1; + optional bool on_disk = 1 [deprecated = true]; // Enable HNSW graph building for this payload field. // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 2; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 3; } message DatetimeIndexParams { + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 1; + optional bool on_disk = 1 [deprecated = true]; // If true - use this key to organize storage of the collection data. // This option assumes that this key will be used in majority of filtered requests. optional bool is_principal = 2; @@ -724,17 +833,24 @@ message DatetimeIndexParams { // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 3; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 4; } message UuidIndexParams { // If true - used for tenant optimization. optional bool is_tenant = 1; + // Deprecated: use `memory` instead. // If true - store index on disk. - optional bool on_disk = 2; + optional bool on_disk = 2 [deprecated = true]; // Enable HNSW graph building for this payload field. // If true, builds additional HNSW links (Need payload_m > 0). // Default: true. optional bool enable_hnsw = 3; + // Memory placement of the index. + // Overrides the deprecated `on_disk` flag if both are set. + optional Memory memory = 4; } message PayloadIndexParams { @@ -964,6 +1080,8 @@ message CollectionClusterInfoResponse { repeated ShardTransferInfo shard_transfers = 5; // Resharding operations repeated ReshardingInfo resharding_operations = 6; + // Time spent to process + double time = 7; } message MoveShard { @@ -1064,6 +1182,8 @@ message UpdateCollectionClusterSetupRequest { message UpdateCollectionClusterSetupResponse { bool result = 1; + // Time spent to process + double time = 2; } message CreateShardKeyRequest { @@ -1093,10 +1213,14 @@ message ListShardKeysRequest { message CreateShardKeyResponse { bool result = 1; + // Time spent to process + double time = 2; } message DeleteShardKeyResponse { bool result = 1; + // Time spent to process + double time = 2; } message ShardKeyDescription { diff --git a/proto/points.proto b/proto/points.proto index 767d4cb3..0af10e98 100644 --- a/proto/points.proto +++ b/proto/points.proto @@ -362,7 +362,7 @@ message DenseVectorCreationConfig { Distance distance = 2; // Configuration for multi-vector search (e.g., ColBERT) optional MultiVectorConfig multivector_config = 3; - // Data type of the vectors (Float32, Float16, Uint8) + // Data type of the vectors (Float32, Float16, Uint8, Turbo4) optional Datatype datatype = 4; } @@ -500,6 +500,14 @@ message AcornSearchParams { optional double max_selectivity = 2; } +// Population over which sparse vector IDF statistics are computed for scoring - the IDF corpus. +// Only applicable to sparse vectors with the IDF modifier enabled. +message IdfParams { + // Filter defining the corpus: IDF statistics are computed over the points matching this filter. + // If unset, statistics are collection-wide (global) - same as omitting `idf` entirely. + optional Filter corpus = 1; +} + message SearchParams { // Params relevant to HNSW index. Size of the beam in a beam-search. // Larger the value - more accurate the result, more time required for search. @@ -517,6 +525,10 @@ message SearchParams { // ACORN search params optional AcornSearchParams acorn = 5; + + // Which population sparse vector IDF statistics are computed over. + // If unset, statistics are collection-wide (global). + optional IdfParams idf = 6; } message SearchPoints { diff --git a/proto/qdrant_common.proto b/proto/qdrant_common.proto index 770fec24..71a72469 100644 --- a/proto/qdrant_common.proto +++ b/proto/qdrant_common.proto @@ -45,6 +45,7 @@ message Condition { IsNullCondition is_null = 5; NestedCondition nested = 6; HasVectorCondition has_vector = 7; + SliceCondition slice = 8; } } @@ -64,6 +65,13 @@ message HasVectorCondition { string has_vector = 1; } +message SliceCondition { + // Total number of disjoint deterministic slices the id space is split into, must be >= 1 + uint32 total = 1; + // Which slice to select, must be less than `total` + uint32 index = 2; +} + message NestedCondition { // Path to nested object string key = 1; @@ -115,6 +123,8 @@ message Match { string phrase = 9; // Match any word in the text string text_any = 10; + // Match keywords starting with the given prefix + string prefix = 11; } } diff --git a/src/builders/binary_quantization_builder.rs b/src/builders/binary_quantization_builder.rs index d8a3f206..29e78edb 100644 --- a/src/builders/binary_quantization_builder.rs +++ b/src/builders/binary_quantization_builder.rs @@ -7,10 +7,13 @@ pub struct BinaryQuantizationBuilder { pub(crate) always_ram: Option>, pub(crate) encoding: Option>, pub(crate) query_encoding: Option>, + /// Memory placement of quantized vectors. + pub(crate) memory: Option>, } impl BinaryQuantizationBuilder { /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Some(Some(value)); @@ -33,11 +36,21 @@ impl BinaryQuantizationBuilder { new } + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + pub fn memory(self, value: impl Into) -> Self { + let mut new = self; + new.memory = Some(Some(value.into())); + new + } + + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(BinaryQuantization { always_ram: self.always_ram.unwrap_or_default(), encoding: self.encoding.unwrap_or_default(), query_encoding: self.query_encoding.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -46,6 +59,7 @@ impl BinaryQuantizationBuilder { always_ram: Default::default(), encoding: Default::default(), query_encoding: Default::default(), + memory: Default::default(), } } } @@ -79,6 +93,12 @@ impl BinaryQuantizationBuilder { } } +impl Default for BinaryQuantizationBuilder { + fn default() -> Self { + Self::create_empty() + } +} + #[non_exhaustive] #[derive(Debug)] pub enum BinaryQuantizationBuilderError { diff --git a/src/builders/bool_index_params_builder.rs b/src/builders/bool_index_params_builder.rs index d0e23468..c599a3d4 100644 --- a/src/builders/bool_index_params_builder.rs +++ b/src/builders/bool_index_params_builder.rs @@ -7,6 +7,8 @@ pub struct BoolIndexParamsBuilder { pub(crate) on_disk: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl Default for BoolIndexParamsBuilder { @@ -21,6 +23,7 @@ impl BoolIndexParamsBuilder { } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -32,11 +35,20 @@ impl BoolIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(BoolIndexParams { on_disk: self.on_disk.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -44,6 +56,7 @@ impl BoolIndexParamsBuilder { Self { on_disk: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/collection_params_diff_builder.rs b/src/builders/collection_params_diff_builder.rs index d23fd413..1180f17c 100644 --- a/src/builders/collection_params_diff_builder.rs +++ b/src/builders/collection_params_diff_builder.rs @@ -13,6 +13,8 @@ pub struct CollectionParamsDiffBuilder { pub(crate) read_fan_out_factor: Option>, /// Fan-out delay in milliseconds. If set, the fan-out request will be delayed by this amount. pub(crate) read_fan_out_delay_ms: Option>, + /// Update params of the payload storage + pub(crate) payload: Option>, } #[allow(clippy::all)] #[allow(clippy::derive_partial_eq_without_eq)] @@ -30,6 +32,7 @@ impl CollectionParamsDiffBuilder { new } /// If true - point's payload will not be stored in memory + #[deprecated(since = "1.19.0", note = "use `payload` instead")] pub fn on_disk_payload(self, value: bool) -> Self { let mut new = self; new.on_disk_payload = Option::Some(Option::Some(value)); @@ -47,7 +50,15 @@ impl CollectionParamsDiffBuilder { new.read_fan_out_delay_ms = Option::Some(Option::Some(value)); new } + /// Update params of the payload storage. + /// Overrides the deprecated `on_disk_payload` flag if both are set. + pub fn payload>(self, value: VALUE) -> Self { + let mut new = self; + new.payload = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(CollectionParamsDiff { replication_factor: match self.replication_factor { @@ -70,6 +81,10 @@ impl CollectionParamsDiffBuilder { Some(value) => value, None => core::default::Default::default(), }, + payload: match self.payload { + Some(value) => value, + None => core::default::Default::default(), + }, }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -80,6 +95,7 @@ impl CollectionParamsDiffBuilder { on_disk_payload: core::default::Default::default(), read_fan_out_factor: core::default::Default::default(), read_fan_out_delay_ms: core::default::Default::default(), + payload: core::default::Default::default(), } } } diff --git a/src/builders/create_collection_builder.rs b/src/builders/create_collection_builder.rs index 3dd110d5..45c432a1 100644 --- a/src/builders/create_collection_builder.rs +++ b/src/builders/create_collection_builder.rs @@ -37,6 +37,8 @@ pub struct CreateCollectionBuilder { pub(crate) strict_mode_config: Option>, /// Arbitrary JSON metadata for the collection pub(crate) metadata: Option>, + /// Configuration of the payload storage + pub(crate) payload: Option>, } #[allow(clippy::all)] @@ -76,6 +78,7 @@ impl CreateCollectionBuilder { new } /// If true - point's payload will not be stored in memory + #[deprecated(since = "1.19.0", note = "use `payload` instead")] pub fn on_disk_payload(self, value: bool) -> Self { let mut new = self; new.on_disk_payload = Option::Some(Option::Some(value)); @@ -144,7 +147,15 @@ impl CreateCollectionBuilder { new.metadata = Option::Some(value.into().0); new } + /// Configuration of the payload storage. + /// Overrides the deprecated `on_disk_payload` flag if both are set. + pub fn payload>(self, value: VALUE) -> Self { + let mut new = self; + new.payload = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(CreateCollection { collection_name: match self.collection_name { @@ -204,6 +215,10 @@ impl CreateCollectionBuilder { Some(value) => value, None => core::default::Default::default(), }, + payload: match self.payload { + Some(value) => value, + None => core::default::Default::default(), + }, }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -224,6 +239,7 @@ impl CreateCollectionBuilder { sparse_vectors_config: core::default::Default::default(), strict_mode_config: core::default::Default::default(), metadata: core::default::Default::default(), + payload: core::default::Default::default(), } } } diff --git a/src/builders/datetime_index_params_builder.rs b/src/builders/datetime_index_params_builder.rs index eae30716..0466fee3 100644 --- a/src/builders/datetime_index_params_builder.rs +++ b/src/builders/datetime_index_params_builder.rs @@ -9,10 +9,13 @@ pub struct DatetimeIndexParamsBuilder { pub(crate) is_principal: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl DatetimeIndexParamsBuilder { /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -30,12 +33,21 @@ impl DatetimeIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(DatetimeIndexParams { on_disk: self.on_disk.unwrap_or_default(), is_principal: self.is_principal.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -44,6 +56,7 @@ impl DatetimeIndexParamsBuilder { on_disk: core::default::Default::default(), is_principal: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/float_index_params_builder.rs b/src/builders/float_index_params_builder.rs index 82a5e5cc..a3028eda 100644 --- a/src/builders/float_index_params_builder.rs +++ b/src/builders/float_index_params_builder.rs @@ -9,6 +9,8 @@ pub struct FloatIndexParamsBuilder { pub(crate) is_principal: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl Default for FloatIndexParamsBuilder { @@ -23,6 +25,7 @@ impl FloatIndexParamsBuilder { } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -40,12 +43,21 @@ impl FloatIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(FloatIndexParams { on_disk: self.on_disk.unwrap_or_default(), is_principal: self.is_principal.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -54,6 +66,7 @@ impl FloatIndexParamsBuilder { on_disk: core::default::Default::default(), is_principal: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/geo_index_params_builder.rs b/src/builders/geo_index_params_builder.rs index 93c8242f..336ca08b 100644 --- a/src/builders/geo_index_params_builder.rs +++ b/src/builders/geo_index_params_builder.rs @@ -7,6 +7,8 @@ pub struct GeoIndexParamsBuilder { pub(crate) on_disk: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl Default for GeoIndexParamsBuilder { @@ -21,6 +23,7 @@ impl GeoIndexParamsBuilder { } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -32,11 +35,20 @@ impl GeoIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(GeoIndexParams { on_disk: self.on_disk.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -44,6 +56,7 @@ impl GeoIndexParamsBuilder { Self { on_disk: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/hnsw_config_diff_builder.rs b/src/builders/hnsw_config_diff_builder.rs index a3098ec8..01231a01 100644 --- a/src/builders/hnsw_config_diff_builder.rs +++ b/src/builders/hnsw_config_diff_builder.rs @@ -33,6 +33,9 @@ pub struct HnswConfigDiffBuilder { /// random seeks during the search. /// Requires quantized vectors to be enabled. Multi-vectors are not supported. pub(crate) inline_storage: Option>, + /// + /// Memory placement of the HNSW graph. + pub(crate) memory: Option>, } #[allow(clippy::all)] #[allow(clippy::derive_partial_eq_without_eq)] @@ -73,6 +76,7 @@ impl HnswConfigDiffBuilder { } /// /// Store HNSW index on disk. If set to false, the index will be stored in RAM. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -95,7 +99,16 @@ impl HnswConfigDiffBuilder { new.inline_storage = Option::Some(Option::Some(value)); new } + /// + /// Memory placement of the HNSW graph. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(HnswConfigDiff { m: match self.m { @@ -126,6 +139,10 @@ impl HnswConfigDiffBuilder { Some(value) => value, None => core::default::Default::default(), }, + memory: match self.memory { + Some(value) => value, + None => core::default::Default::default(), + }, }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -138,6 +155,7 @@ impl HnswConfigDiffBuilder { on_disk: core::default::Default::default(), payload_m: core::default::Default::default(), inline_storage: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/integer_index_params_builder.rs b/src/builders/integer_index_params_builder.rs index d606c47e..b1887460 100644 --- a/src/builders/integer_index_params_builder.rs +++ b/src/builders/integer_index_params_builder.rs @@ -13,6 +13,8 @@ pub struct IntegerIndexParamsBuilder { pub(crate) on_disk: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl IntegerIndexParamsBuilder { @@ -39,6 +41,7 @@ impl IntegerIndexParamsBuilder { new } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -50,7 +53,15 @@ impl IntegerIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(IntegerIndexParams { lookup: self.lookup.unwrap_or_default(), @@ -58,6 +69,7 @@ impl IntegerIndexParamsBuilder { is_principal: self.is_principal.unwrap_or_default(), on_disk: self.on_disk.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -68,6 +80,7 @@ impl IntegerIndexParamsBuilder { is_principal: core::default::Default::default(), on_disk: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/keyword_index_params_builder.rs b/src/builders/keyword_index_params_builder.rs index 14e7c9d1..b4a8667e 100644 --- a/src/builders/keyword_index_params_builder.rs +++ b/src/builders/keyword_index_params_builder.rs @@ -9,6 +9,10 @@ pub struct KeywordIndexParamsBuilder { pub(crate) on_disk: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// If set - enable prefix matching on this field. + pub(crate) prefix: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl Default for KeywordIndexParamsBuilder { @@ -25,6 +29,7 @@ impl KeywordIndexParamsBuilder { new } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -36,12 +41,28 @@ impl KeywordIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// If true - enable prefix matching (`Condition::matches_prefix`) on this field. + pub fn prefix(self, value: bool) -> Self { + let mut new = self; + new.prefix = Option::Some(value.then(KeywordPrefixParams::default)); + new + } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(KeywordIndexParams { is_tenant: self.is_tenant.unwrap_or_default(), on_disk: self.on_disk.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + prefix: self.prefix.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -50,6 +71,8 @@ impl KeywordIndexParamsBuilder { is_tenant: core::default::Default::default(), on_disk: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + prefix: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/product_quantization_builder.rs b/src/builders/product_quantization_builder.rs index 163406f9..e07019d4 100644 --- a/src/builders/product_quantization_builder.rs +++ b/src/builders/product_quantization_builder.rs @@ -7,6 +7,8 @@ pub struct ProductQuantizationBuilder { pub(crate) compression: Option, /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage pub(crate) always_ram: Option>, + /// Memory placement of quantized vectors. + pub(crate) memory: Option>, } impl ProductQuantizationBuilder { @@ -17,12 +19,21 @@ impl ProductQuantizationBuilder { new } /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Option::Some(Option::Some(value)); new } + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(ProductQuantization { compression: match self.compression { @@ -34,6 +45,7 @@ impl ProductQuantizationBuilder { } }, always_ram: self.always_ram.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -41,6 +53,7 @@ impl ProductQuantizationBuilder { Self { compression: core::default::Default::default(), always_ram: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/scalar_quantization_builder.rs b/src/builders/scalar_quantization_builder.rs index 193c84b9..8d8615a2 100644 --- a/src/builders/scalar_quantization_builder.rs +++ b/src/builders/scalar_quantization_builder.rs @@ -9,6 +9,8 @@ pub struct ScalarQuantizationBuilder { pub(crate) quantile: Option>, /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage pub(crate) always_ram: Option>, + /// Memory placement of quantized vectors. + pub(crate) memory: Option>, } impl ScalarQuantizationBuilder { @@ -25,12 +27,21 @@ impl ScalarQuantizationBuilder { new } /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Option::Some(Option::Some(value)); new } + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(ScalarQuantization { r#type: match self.r#type { @@ -43,6 +54,7 @@ impl ScalarQuantizationBuilder { }, quantile: self.quantile.unwrap_or_default(), always_ram: self.always_ram.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -51,6 +63,7 @@ impl ScalarQuantizationBuilder { r#type: core::default::Default::default(), quantile: core::default::Default::default(), always_ram: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/search_params_builder.rs b/src/builders/search_params_builder.rs index 46cbbcda..c28b644d 100644 --- a/src/builders/search_params_builder.rs +++ b/src/builders/search_params_builder.rs @@ -21,6 +21,9 @@ pub struct SearchParamsBuilder { /// /// Params relevant to ACORN index pub(crate) acorn: Option>, + /// + /// Which population sparse vector IDF statistics are computed over + pub(crate) idf: Option>, } impl SearchParamsBuilder { @@ -65,6 +68,14 @@ impl SearchParamsBuilder { new.acorn = Option::Some(Option::Some(value.into())); new } + /// + /// Which population sparse vector IDF statistics are computed over. + /// If unset, statistics are collection-wide (global). + pub fn idf>(self, value: VALUE) -> Self { + let mut new = self; + new.idf = Option::Some(Option::Some(value.into())); + new + } fn build_inner(self) -> Result { Ok(SearchParams { @@ -73,6 +84,7 @@ impl SearchParamsBuilder { quantization: self.quantization.unwrap_or_default(), indexed_only: self.indexed_only.unwrap_or_default(), acorn: self.acorn.unwrap_or_default(), + idf: self.idf.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -83,6 +95,7 @@ impl SearchParamsBuilder { quantization: core::default::Default::default(), indexed_only: core::default::Default::default(), acorn: core::default::Default::default(), + idf: core::default::Default::default(), } } } diff --git a/src/builders/sparse_index_config_builder.rs b/src/builders/sparse_index_config_builder.rs index efd03b50..68479ac4 100644 --- a/src/builders/sparse_index_config_builder.rs +++ b/src/builders/sparse_index_config_builder.rs @@ -13,6 +13,9 @@ pub struct SparseIndexConfigBuilder { /// /// Datatype used to store weights in the index. pub(crate) datatype: Option>, + /// + /// Memory placement of the index. + pub(crate) memory: Option>, } impl SparseIndexConfigBuilder { @@ -26,6 +29,7 @@ impl SparseIndexConfigBuilder { } /// /// Store inverted index on disk. If set to false, the index will be stored in RAM. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -38,12 +42,22 @@ impl SparseIndexConfigBuilder { new.datatype = Option::Some(Option::Some(value.into())); new } + /// + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(SparseIndexConfig { full_scan_threshold: self.full_scan_threshold.unwrap_or_default(), on_disk: self.on_disk.unwrap_or_default(), datatype: self.datatype.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -52,6 +66,7 @@ impl SparseIndexConfigBuilder { full_scan_threshold: core::default::Default::default(), on_disk: core::default::Default::default(), datatype: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/strict_mode_config_builder.rs b/src/builders/strict_mode_config_builder.rs index d6db77f6..03a3f1e3 100644 --- a/src/builders/strict_mode_config_builder.rs +++ b/src/builders/strict_mode_config_builder.rs @@ -24,6 +24,7 @@ pub struct StrictModeConfigBuilder { pub(crate) max_points_count: Option>, pub(crate) max_payload_index_count: Option>, pub(crate) max_resident_memory_percent: Option>, + pub(crate) max_disk_usage_percent: Option>, } impl StrictModeConfigBuilder { @@ -153,6 +154,14 @@ impl StrictModeConfigBuilder { new } + /// Reject disk-consuming update operations when the filesystem hosting Qdrant storage + /// exceeds this percentage of total capacity (1-100). + pub fn max_disk_usage_percent(self, value: u32) -> Self { + let mut new = self; + new.max_disk_usage_percent = Option::Some(Option::Some(value)); + new + } + fn build_inner(self) -> Result { Ok(StrictModeConfig { enabled: self.enabled.unwrap_or_default(), @@ -180,6 +189,7 @@ impl StrictModeConfigBuilder { max_points_count: self.max_points_count.unwrap_or_default(), max_payload_index_count: self.max_payload_index_count.unwrap_or_default(), max_resident_memory_percent: self.max_resident_memory_percent.unwrap_or_default(), + max_disk_usage_percent: self.max_disk_usage_percent.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -206,6 +216,7 @@ impl StrictModeConfigBuilder { max_points_count: core::default::Default::default(), max_payload_index_count: core::default::Default::default(), max_resident_memory_percent: core::default::Default::default(), + max_disk_usage_percent: core::default::Default::default(), } } } diff --git a/src/builders/text_index_params_builder.rs b/src/builders/text_index_params_builder.rs index 47cd6c75..ba7d2552 100644 --- a/src/builders/text_index_params_builder.rs +++ b/src/builders/text_index_params_builder.rs @@ -22,6 +22,8 @@ pub struct TextIndexParamsBuilder { pub(crate) ascii_folding: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl TextIndexParamsBuilder { @@ -56,6 +58,7 @@ impl TextIndexParamsBuilder { new } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -99,6 +102,18 @@ impl TextIndexParamsBuilder { new } + /// Explicitly disable stemming, overriding the language default + pub fn disabled_stemmer(self) -> Self { + let mut new = self; + let stemmer = StemmingAlgorithm { + stemming_params: Some(stemming_algorithm::StemmingParams::Disabled( + DisabledStemmer {}, + )), + }; + new.stemmer = Some(Some(stemmer)); + new + } + /// Set an algorithm for stemming. pub fn stemmer(self, stemming_params: stemming_algorithm::StemmingParams) -> Self { let mut new = self; @@ -123,6 +138,15 @@ impl TextIndexParamsBuilder { new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(TextIndexParams { tokenizer: match self.tokenizer { @@ -142,6 +166,7 @@ impl TextIndexParamsBuilder { stemmer: self.stemmer.unwrap_or_default(), ascii_folding: self.ascii_folding.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } @@ -158,6 +183,7 @@ impl TextIndexParamsBuilder { stemmer: Default::default(), ascii_folding: Default::default(), enable_hnsw: Default::default(), + memory: Default::default(), } } } diff --git a/src/builders/turbo_quantization_builder.rs b/src/builders/turbo_quantization_builder.rs index 07738793..d5586f11 100644 --- a/src/builders/turbo_quantization_builder.rs +++ b/src/builders/turbo_quantization_builder.rs @@ -6,10 +6,13 @@ pub struct TurboQuantizationBuilder { /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage pub(crate) always_ram: Option>, pub(crate) bits: Option>, + /// Memory placement of quantized vectors. + pub(crate) memory: Option>, } impl TurboQuantizationBuilder { /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Some(Some(value)); @@ -24,10 +27,20 @@ impl TurboQuantizationBuilder { new } + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + pub fn memory(self, value: impl Into) -> Self { + let mut new = self; + new.memory = Some(Some(value.into())); + new + } + + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(TurboQuantization { always_ram: self.always_ram.unwrap_or_default(), bits: self.bits.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } @@ -36,6 +49,7 @@ impl TurboQuantizationBuilder { Self { always_ram: Default::default(), bits: Default::default(), + memory: Default::default(), } } } diff --git a/src/builders/uuid_index_params_builder.rs b/src/builders/uuid_index_params_builder.rs index 763e0835..8e80002f 100644 --- a/src/builders/uuid_index_params_builder.rs +++ b/src/builders/uuid_index_params_builder.rs @@ -9,6 +9,8 @@ pub struct UuidIndexParamsBuilder { pub(crate) on_disk: Option>, /// If true - enable HNSW index for this field. pub(crate) enable_hnsw: Option>, + /// Memory placement of the index. + pub(crate) memory: Option>, } impl UuidIndexParamsBuilder { @@ -19,6 +21,7 @@ impl UuidIndexParamsBuilder { new } /// If true - store index on disk. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -30,12 +33,21 @@ impl UuidIndexParamsBuilder { new.enable_hnsw = Option::Some(Option::Some(value)); new } + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(UuidIndexParams { is_tenant: self.is_tenant.unwrap_or_default(), on_disk: self.on_disk.unwrap_or_default(), enable_hnsw: self.enable_hnsw.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -44,6 +56,7 @@ impl UuidIndexParamsBuilder { is_tenant: core::default::Default::default(), on_disk: core::default::Default::default(), enable_hnsw: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/vector_params_builder.rs b/src/builders/vector_params_builder.rs index 5401d1b9..c33b8e46 100644 --- a/src/builders/vector_params_builder.rs +++ b/src/builders/vector_params_builder.rs @@ -18,6 +18,8 @@ pub struct VectorParamsBuilder { pub(crate) datatype: Option>, /// Configuration for multi-vector search pub(crate) multivector_config: Option>, + /// Memory placement of the original vector storage. + pub(crate) memory: Option>, } impl VectorParamsBuilder { @@ -49,6 +51,7 @@ impl VectorParamsBuilder { new } /// If true - serve vectors from disk. If set to false, the vectors will be loaded in RAM. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); @@ -69,7 +72,16 @@ impl VectorParamsBuilder { new.multivector_config = Option::Some(Option::Some(value.into())); new } + /// Memory placement of the original vector storage. + /// Overrides the deprecated `on_disk` flag if both are set. + /// [`Memory::Pinned`] is not supported for dense vector storage. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(VectorParams { size: self.size.unwrap_or_default(), @@ -79,6 +91,7 @@ impl VectorParamsBuilder { on_disk: self.on_disk.unwrap_or_default(), datatype: self.datatype.unwrap_or_default(), multivector_config: self.multivector_config.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -91,6 +104,7 @@ impl VectorParamsBuilder { on_disk: core::default::Default::default(), datatype: core::default::Default::default(), multivector_config: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/builders/vector_params_diff_builder.rs b/src/builders/vector_params_diff_builder.rs index 970057a4..31b45dfc 100644 --- a/src/builders/vector_params_diff_builder.rs +++ b/src/builders/vector_params_diff_builder.rs @@ -10,6 +10,8 @@ pub struct VectorParamsDiffBuilder { quantization_config: Option, /// If true - serve vectors from disk. If set to false, the vectors will be loaded in RAM. pub(crate) on_disk: Option>, + /// Memory placement of the original vector storage. + pub(crate) memory: Option>, } impl VectorParamsDiffBuilder { @@ -31,17 +33,28 @@ impl VectorParamsDiffBuilder { new } /// If true - serve vectors from disk. If set to false, the vectors will be loaded in RAM. + #[deprecated(since = "1.19.0", note = "use `memory` instead")] pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); new } + /// Memory placement of the original vector storage. + /// Overrides the deprecated `on_disk` flag if both are set. + /// [`Memory::Pinned`] is not supported for dense vector storage. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + #[allow(deprecated)] fn build_inner(self) -> Result { Ok(VectorParamsDiff { hnsw_config: self.hnsw_config.unwrap_or_default(), quantization_config: { convert_option(&self.quantization_config) }, on_disk: self.on_disk.unwrap_or_default(), + memory: self.memory.unwrap_or_default(), }) } /// Create an empty builder, with all fields set to `None` or `PhantomData`. @@ -50,6 +63,7 @@ impl VectorParamsDiffBuilder { hnsw_config: core::default::Default::default(), quantization_config: core::default::Default::default(), on_disk: core::default::Default::default(), + memory: core::default::Default::default(), } } } diff --git a/src/filters.rs b/src/filters.rs index c25e5971..8a9369ee 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -4,7 +4,7 @@ use crate::qdrant::r#match::MatchValue; use crate::qdrant::{ self, Condition, DatetimeRange, FieldCondition, Filter, GeoBoundingBox, GeoPolygon, GeoRadius, HasIdCondition, HasVectorCondition, IsEmptyCondition, IsNullCondition, MinShould, - NestedCondition, PointId, PointsSelector, Range, ValuesCount, + NestedCondition, PointId, PointsSelector, Range, SliceCondition, ValuesCount, }; impl From for PointsSelector { @@ -55,6 +55,14 @@ impl From for Condition { } } +impl From for Condition { + fn from(slice_condition: SliceCondition) -> Self { + Condition { + condition_one_of: Some(ConditionOneOf::Slice(slice_condition)), + } + } +} + impl From for Condition { fn from(filter: Filter) -> Self { Condition { @@ -273,6 +281,45 @@ impl qdrant::Condition { } } + /// Create a [`Condition`] to match keywords starting with the given prefix. + /// + /// Requires the keyword index of the field to be created with prefix matching enabled, + /// see [`KeywordIndexParamsBuilder::prefix`](qdrant::KeywordIndexParamsBuilder::prefix). + /// + /// # Examples: + /// ``` + /// qdrant_client::qdrant::Condition::matches_prefix("city", "Ber"); + /// ``` + pub fn matches_prefix(field: impl Into, prefix: impl Into) -> Self { + Self { + condition_one_of: Some(ConditionOneOf::Field(qdrant::FieldCondition { + key: field.into(), + r#match: Some(qdrant::Match { + match_value: Some(MatchValue::Prefix(prefix.into())), + }), + ..Default::default() + })), + } + } + + /// Create a [`Condition`] selecting one of `total` disjoint deterministic slices of the id + /// space. Useful to split a collection into equally sized chunks, for example to scroll + /// through it in parallel. + /// + /// `index` must be less than `total`. + /// + /// # Examples: + /// ``` + /// // Select the first of four slices of the collection + /// qdrant_client::qdrant::Condition::slice(4, 0); + /// ``` + pub fn slice(total: u32, index: u32) -> Self { + debug_assert!(total >= 1, "`total` must be at least 1"); + debug_assert!(index < total, "`index` must be less than `total`"); + + Self::from(SliceCondition { total, index }) + } + /// Create a [`Condition`] that checks numeric fields against a range. /// /// # Examples: @@ -490,6 +537,9 @@ impl std::ops::Not for MatchValue { Self::TextAny(_) => { panic!("cannot negate a MatchValue::TextAny, use within must_not clause instead") } + Self::Prefix(_) => { + panic!("cannot negate a MatchValue::Prefix, use within must_not clause instead") + } } } } diff --git a/src/grpc_conversions/mod.rs b/src/grpc_conversions/mod.rs index 8191e3a0..dc8552cc 100644 --- a/src/grpc_conversions/mod.rs +++ b/src/grpc_conversions/mod.rs @@ -15,17 +15,18 @@ use crate::qdrant::{ AbortShardTransfer, AbortShardTransferBuilder, AliasOperations, BinaryQuantization, BinaryQuantizationBuilder, Condition, CreateAlias, CreateShardKey, DeleteAlias, DeleteShardKey, DenseVectorCreationConfig, DenseVectorCreationConfigBuilder, Disabled, FieldCondition, Filter, - GeoLineString, GeoPoint, GroupId, HasIdCondition, IsEmptyCondition, IsNullCondition, ListValue, - Match, MoveShard, MoveShardBuilder, NestedCondition, PayloadExcludeSelector, - PayloadIncludeSelector, PointId, PointsIdsList, PointsSelector, PointsUpdateOperation, - ProductQuantization, ProductQuantizationBuilder, QuantizationConfig, QuantizationConfigDiff, - ReadConsistency, RenameAlias, Replica, ReplicateShard, ReplicateShardBuilder, RestartTransfer, - ScalarQuantization, ScalarQuantizationBuilder, ShardKey, ShardKeySelector, SparseIndexConfig, - SparseVectorCreationConfig, SparseVectorCreationConfigBuilder, SparseVectorParams, StartFrom, - Struct, TargetVector, TurboQuantization, TurboQuantizationBuilder, Value, Vector, - VectorExample, VectorParams, VectorParamsBuilder, VectorParamsDiff, VectorParamsDiffBuilder, - VectorParamsDiffMap, VectorParamsMap, VectorsConfig, VectorsConfigDiff, VectorsSelector, - WithPayloadSelector, WithVectorsSelector, + GeoLineString, GeoPoint, GroupId, HasIdCondition, IdfParams, IsEmptyCondition, IsNullCondition, + ListValue, Match, Memory, MoveShard, MoveShardBuilder, NestedCondition, PayloadExcludeSelector, + PayloadIncludeSelector, PayloadStorageParams, PointId, PointsIdsList, PointsSelector, + PointsUpdateOperation, ProductQuantization, ProductQuantizationBuilder, QuantizationConfig, + QuantizationConfigDiff, ReadConsistency, RenameAlias, Replica, ReplicateShard, + ReplicateShardBuilder, RestartTransfer, ScalarQuantization, ScalarQuantizationBuilder, + ShardKey, ShardKeySelector, SliceCondition, SparseIndexConfig, SparseVectorCreationConfig, + SparseVectorCreationConfigBuilder, SparseVectorParams, StartFrom, Struct, TargetVector, + TurboQuantization, TurboQuantizationBuilder, Value, Vector, VectorExample, VectorParams, + VectorParamsBuilder, VectorParamsDiff, VectorParamsDiffBuilder, VectorParamsDiffMap, + VectorParamsMap, VectorsConfig, VectorsConfigDiff, VectorsSelector, WithPayloadSelector, + WithVectorsSelector, }; impl From> for PointsSelector { @@ -410,6 +411,12 @@ impl From for condition::ConditionOneOf { } } +impl From for condition::ConditionOneOf { + fn from(value: SliceCondition) -> Self { + Self::Slice(value) + } +} + impl From> for HasIdCondition { fn from(value: Vec) -> Self { Self { has_id: value } @@ -524,6 +531,22 @@ impl From for quantization_config::Quantization { } } +impl From for PayloadStorageParams { + fn from(value: Memory) -> Self { + Self { + memory: Some(value.into()), + } + } +} + +impl From for IdfParams { + fn from(value: Filter) -> Self { + Self { + corpus: Some(value), + } + } +} + impl From for points_update_operation::Operation { fn from(value: points_update_operation::PointStructList) -> Self { Self::Upsert(value) diff --git a/src/qdrant.rs b/src/qdrant.rs index 108d9184..bafb4450 100644 --- a/src/qdrant.rs +++ b/src/qdrant.rs @@ -138,7 +138,7 @@ pub struct MinShould { } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Condition { - #[prost(oneof = "condition::ConditionOneOf", tags = "1, 2, 3, 4, 5, 6, 7")] + #[prost(oneof = "condition::ConditionOneOf", tags = "1, 2, 3, 4, 5, 6, 7, 8")] pub condition_one_of: ::core::option::Option, } /// Nested message and enum types in `Condition`. @@ -159,6 +159,8 @@ pub mod condition { Nested(super::NestedCondition), #[prost(message, tag = "7")] HasVector(super::HasVectorCondition), + #[prost(message, tag = "8")] + Slice(super::SliceCondition), } } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] @@ -181,6 +183,15 @@ pub struct HasVectorCondition { #[prost(string, tag = "1")] pub has_vector: ::prost::alloc::string::String, } +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct SliceCondition { + /// Total number of disjoint deterministic slices the id space is split into, must be >= 1 + #[prost(uint32, tag = "1")] + pub total: u32, + /// Which slice to select, must be less than `total` + #[prost(uint32, tag = "2")] + pub index: u32, +} #[derive(Clone, PartialEq, ::prost::Message)] pub struct NestedCondition { /// Path to nested object @@ -224,7 +235,7 @@ pub struct FieldCondition { } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Match { - #[prost(oneof = "r#match::MatchValue", tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10")] + #[prost(oneof = "r#match::MatchValue", tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11")] pub match_value: ::core::option::Option, } /// Nested message and enum types in `Match`. @@ -261,6 +272,9 @@ pub mod r#match { /// Match any word in the text #[prost(string, tag = "10")] TextAny(::prost::alloc::string::String), + /// Match keywords starting with the given prefix + #[prost(string, tag = "11")] + Prefix(::prost::alloc::string::String), } } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] @@ -358,8 +372,10 @@ pub struct VectorParams { /// If omitted - the collection configuration will be used #[prost(message, optional, tag = "4")] pub quantization_config: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - serve vectors from disk. /// If set to false, the vectors will be loaded in RAM. + #[deprecated] #[prost(bool, optional, tag = "5")] pub on_disk: ::core::option::Option, /// Data type of the vectors @@ -368,6 +384,11 @@ pub struct VectorParams { /// Configuration for multi-vector search #[prost(message, optional, tag = "7")] pub multivector_config: ::core::option::Option, + /// Memory placement of the original vector storage. + /// Overrides the deprecated `on_disk` flag if both are set. + /// `Pinned` is not supported for dense vector storage. + #[prost(enumeration = "Memory", optional, tag = "8")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct VectorParamsDiff { @@ -378,10 +399,17 @@ pub struct VectorParamsDiff { /// Update quantization params. If none - it is left unchanged. #[prost(message, optional, tag = "2")] pub quantization_config: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - serve vectors from disk. /// If set to false, the vectors will be loaded in RAM. + #[deprecated] #[prost(bool, optional, tag = "3")] pub on_disk: ::core::option::Option, + /// Memory placement of the original vector storage. + /// Overrides the deprecated `on_disk` flag if both are set. + /// `Pinned` is not supported for dense vector storage. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct VectorParamsMap { @@ -581,7 +609,9 @@ pub struct HnswConfigDiff { /// On small CPUs, less threads are used. #[prost(uint64, optional, tag = "4")] pub max_indexing_threads: ::core::option::Option, + /// Deprecated: use `memory` instead. /// Store HNSW index on disk. If set to false, the index will be stored in RAM. + #[deprecated] #[prost(bool, optional, tag = "5")] pub on_disk: ::core::option::Option, /// Number of additional payload-aware links per node in the index graph. @@ -594,6 +624,10 @@ pub struct HnswConfigDiff { /// Requires quantized vectors to be enabled. Multi-vectors are not supported. #[prost(bool, optional, tag = "7")] pub inline_storage: ::core::option::Option, + /// Memory placement of the HNSW graph. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "8")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct SparseIndexConfig { @@ -601,12 +635,18 @@ pub struct SparseIndexConfig { /// Note: this is number of vectors, not KiloBytes. #[prost(uint64, optional, tag = "1")] pub full_scan_threshold: ::core::option::Option, + /// Deprecated: use `memory` instead. /// Store inverted index on disk. If set to false, the index will be stored in RAM. + #[deprecated] #[prost(bool, optional, tag = "2")] pub on_disk: ::core::option::Option, /// Datatype used to store weights in the index. #[prost(enumeration = "Datatype", optional, tag = "3")] pub datatype: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct WalConfigDiff { @@ -685,10 +725,14 @@ pub struct OptimizersConfigDiff { /// If 0 - no optimization threads, optimizations will be disabled. #[prost(message, optional, tag = "9")] pub max_optimization_threads: ::core::option::Option, - /// If this option is set, service will try to prevent creation of large unoptimized segments. - /// When enabled, updates may be blocked at request level if there are unoptimized segments larger than indexing threshold. - /// Updates will be resumed when optimization is completed and segments are optimized below the threshold. - /// Using this option may lead to increased delay between submitting an update and its application. + /// If enabled, the service will try to prevent the creation of large unoptimized segments. + /// When enabled, new points written to segments larger than the indexing threshold are stored + /// as "deferred points": they are persisted in the WAL and segments, but excluded from + /// read/search results until the corresponding segments are optimized (e.g. indexed, + /// quantized, or moved to mmap storage). + /// Update requests with wait=true will only return after the deferred points become visible, + /// which may significantly increase the perceived latency between submitting an update and its + /// completion. Update requests with wait=false are not affected. /// Default is disabled. #[prost(bool, optional, tag = "10")] pub prevent_unoptimized: ::core::option::Option, @@ -701,18 +745,30 @@ pub struct ScalarQuantization { /// Number of bits to use for quantization #[prost(float, optional, tag = "2")] pub quantile: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated] #[prost(bool, optional, tag = "3")] pub always_ram: ::core::option::Option, + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ProductQuantization { /// Compression ratio #[prost(enumeration = "CompressionRatio", tag = "1")] pub compression: i32, + /// Deprecated: use `memory` instead. /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated] #[prost(bool, optional, tag = "2")] pub always_ram: ::core::option::Option, + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "3")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BinaryQuantizationQueryEncoding { @@ -771,7 +827,9 @@ pub mod binary_quantization_query_encoding { } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BinaryQuantization { + /// Deprecated: use `memory` instead. /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage + #[deprecated] #[prost(bool, optional, tag = "1")] pub always_ram: ::core::option::Option, /// Binary quantization encoding method @@ -782,13 +840,23 @@ pub struct BinaryQuantization { /// It can increase the accuracy of search at the cost of performance. #[prost(message, optional, tag = "3")] pub query_encoding: ::core::option::Option, + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TurboQuantization { + /// Deprecated: use `memory` instead. + #[deprecated] #[prost(bool, optional, tag = "1")] pub always_ram: ::core::option::Option, #[prost(enumeration = "TurboQuantBitSize", optional, tag = "2")] pub bits: ::core::option::Option, + /// Memory placement of quantized vectors. + /// Overrides the deprecated `always_ram` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "3")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct QuantizationConfig { @@ -898,6 +966,10 @@ pub struct StrictModeConfig { /// Delete-style operations are still allowed so memory can be freed. #[prost(uint32, optional, tag = "21")] pub max_resident_memory_percent: ::core::option::Option, + /// Reject disk-consuming update operations when the filesystem hosting Qdrant storage exceeds this percentage of total capacity (1-100). + /// Free space is sampled with a small TTL cache so the gate may take a few seconds to react. Delete-style operations are still allowed so disk can be freed. + #[prost(uint32, optional, tag = "22")] + pub max_disk_usage_percent: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct StrictModeSparseConfig { @@ -927,6 +999,15 @@ pub struct StrictModeMultivector { #[prost(uint64, optional, tag = "1")] pub max_vectors: ::core::option::Option, } +/// Params of the payload storage +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PayloadStorageParams { + /// Memory placement of the payload storage. + /// Overrides the deprecated `on_disk_payload` flag if both are set. + /// `Pinned` is not supported for payload storage. + #[prost(enumeration = "Memory", optional, tag = "1")] + pub memory: ::core::option::Option, +} #[derive(Clone, PartialEq, ::prost::Message)] pub struct CreateCollection { /// Name of the collection @@ -945,7 +1026,9 @@ pub struct CreateCollection { /// equal to the number of nodes. Minimum is 1 #[prost(uint32, optional, tag = "7")] pub shard_number: ::core::option::Option, + /// Deprecated: use `payload.memory` instead. /// If true - point's payload will not be stored in memory + #[deprecated] #[prost(bool, optional, tag = "8")] pub on_disk_payload: ::core::option::Option, /// Wait timeout for operation commit in seconds, if not specified - default @@ -976,6 +1059,9 @@ pub struct CreateCollection { /// Arbitrary JSON metadata for the collection #[prost(map = "string, message", tag = "18")] pub metadata: ::std::collections::HashMap<::prost::alloc::string::String, Value>, + /// Configuration of the payload storage + #[prost(message, optional, tag = "19")] + pub payload: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdateCollection { @@ -1038,7 +1124,9 @@ pub struct CollectionParams { /// Number of shards in collection #[prost(uint32, tag = "3")] pub shard_number: u32, + /// Deprecated: use `payload.memory` instead. /// If true - point's payload will not be stored in memory + #[deprecated] #[prost(bool, tag = "4")] pub on_disk_payload: bool, /// Configuration for vectors @@ -1062,6 +1150,9 @@ pub struct CollectionParams { /// Define number of milliseconds to wait before attempting to read from another replica. #[prost(uint64, optional, tag = "11")] pub read_fan_out_delay_ms: ::core::option::Option, + /// Configuration of the payload storage + #[prost(message, optional, tag = "12")] + pub payload: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CollectionParamsDiff { @@ -1071,7 +1162,9 @@ pub struct CollectionParamsDiff { /// How many replicas should apply the operation for us to consider it successful #[prost(uint32, optional, tag = "2")] pub write_consistency_factor: ::core::option::Option, + /// Deprecated: use `payload.memory` instead. /// If true - point's payload will not be stored in memory + #[deprecated] #[prost(bool, optional, tag = "3")] pub on_disk_payload: ::core::option::Option, /// Fan-out every read request to these many additional remote nodes (and return first available response) @@ -1080,6 +1173,9 @@ pub struct CollectionParamsDiff { /// Define number of milliseconds to wait before attempting to read from another replica. #[prost(uint64, optional, tag = "5")] pub read_fan_out_delay_ms: ::core::option::Option, + /// Update params of the payload storage + #[prost(message, optional, tag = "6")] + pub payload: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct CollectionConfig { @@ -1110,7 +1206,9 @@ pub struct KeywordIndexParams { /// If true - used for tenant optimization. #[prost(bool, optional, tag = "1")] pub is_tenant: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "2")] pub on_disk: ::core::option::Option, /// Enable HNSW graph building for this payload field. @@ -1118,7 +1216,18 @@ pub struct KeywordIndexParams { /// Default: true. #[prost(bool, optional, tag = "3")] pub enable_hnsw: ::core::option::Option, -} + /// If set, enable prefix matching (`match: { "prefix": ... }`) on this field. + #[prost(message, optional, tag = "4")] + pub prefix: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "5")] + pub memory: ::core::option::Option, +} +/// Prefix matching options for the keyword index. Has no options yet: +/// presence of this message enables prefix matching. +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct KeywordPrefixParams {} #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct IntegerIndexParams { /// If true - support direct lookups. Default is true. @@ -1132,7 +1241,9 @@ pub struct IntegerIndexParams { /// Default is false. #[prost(bool, optional, tag = "3")] pub is_principal: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - store index on disk. Default is false. + #[deprecated] #[prost(bool, optional, tag = "4")] pub on_disk: ::core::option::Option, /// Enable HNSW graph building for this payload field. @@ -1140,10 +1251,16 @@ pub struct IntegerIndexParams { /// Default: true. #[prost(bool, optional, tag = "5")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "6")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct FloatIndexParams { + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "1")] pub on_disk: ::core::option::Option, /// If true - use this key to organize storage of the collection data. @@ -1155,10 +1272,16 @@ pub struct FloatIndexParams { /// Default: true. #[prost(bool, optional, tag = "3")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct GeoIndexParams { + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "1")] pub on_disk: ::core::option::Option, /// Enable HNSW graph building for this payload field. @@ -1166,6 +1289,10 @@ pub struct GeoIndexParams { /// Default: true. #[prost(bool, optional, tag = "2")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "3")] + pub memory: ::core::option::Option, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StopwordsSet { @@ -1190,7 +1317,9 @@ pub struct TextIndexParams { /// Maximal token length #[prost(uint64, optional, tag = "4")] pub max_token_len: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "5")] pub on_disk: ::core::option::Option, /// Stopwords for the text index @@ -1211,10 +1340,14 @@ pub struct TextIndexParams { /// Default: true. #[prost(bool, optional, tag = "10")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "11")] + pub memory: ::core::option::Option, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StemmingAlgorithm { - #[prost(oneof = "stemming_algorithm::StemmingParams", tags = "1")] + #[prost(oneof = "stemming_algorithm::StemmingParams", tags = "1, 2")] pub stemming_params: ::core::option::Option, } /// Nested message and enum types in `StemmingAlgorithm`. @@ -1224,6 +1357,9 @@ pub mod stemming_algorithm { /// Parameters for snowball stemming #[prost(message, tag = "1")] Snowball(super::SnowballParams), + /// Explicitly disable stemming (overrides the language default) + #[prost(message, tag = "2")] + Disabled(super::DisabledStemmer), } } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] @@ -1232,9 +1368,14 @@ pub struct SnowballParams { #[prost(string, tag = "1")] pub language: ::prost::alloc::string::String, } +/// Marker selecting the "no stemming" algorithm. +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct DisabledStemmer {} #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BoolIndexParams { + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "1")] pub on_disk: ::core::option::Option, /// Enable HNSW graph building for this payload field. @@ -1242,10 +1383,16 @@ pub struct BoolIndexParams { /// Default: true. #[prost(bool, optional, tag = "2")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "3")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DatetimeIndexParams { + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "1")] pub on_disk: ::core::option::Option, /// If true - use this key to organize storage of the collection data. @@ -1257,13 +1404,19 @@ pub struct DatetimeIndexParams { /// Default: true. #[prost(bool, optional, tag = "3")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct UuidIndexParams { /// If true - used for tenant optimization. #[prost(bool, optional, tag = "1")] pub is_tenant: ::core::option::Option, + /// Deprecated: use `memory` instead. /// If true - store index on disk. + #[deprecated] #[prost(bool, optional, tag = "2")] pub on_disk: ::core::option::Option, /// Enable HNSW graph building for this payload field. @@ -1271,6 +1424,10 @@ pub struct UuidIndexParams { /// Default: true. #[prost(bool, optional, tag = "3")] pub enable_hnsw: ::core::option::Option, + /// Memory placement of the index. + /// Overrides the deprecated `on_disk` flag if both are set. + #[prost(enumeration = "Memory", optional, tag = "4")] + pub memory: ::core::option::Option, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PayloadIndexParams { @@ -1540,6 +1697,9 @@ pub struct CollectionClusterInfoResponse { /// Resharding operations #[prost(message, repeated, tag = "6")] pub resharding_operations: ::prost::alloc::vec::Vec, + /// Time spent to process + #[prost(double, tag = "7")] + pub time: f64, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct MoveShard { @@ -1677,10 +1837,13 @@ pub mod update_collection_cluster_setup_request { ReplicatePoints(super::ReplicatePoints), } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct UpdateCollectionClusterSetupResponse { #[prost(bool, tag = "1")] pub result: bool, + /// Time spent to process + #[prost(double, tag = "2")] + pub time: f64, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct CreateShardKeyRequest { @@ -1714,15 +1877,21 @@ pub struct ListShardKeysRequest { #[prost(string, tag = "1")] pub collection_name: ::prost::alloc::string::String, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct CreateShardKeyResponse { #[prost(bool, tag = "1")] pub result: bool, + /// Time spent to process + #[prost(double, tag = "2")] + pub time: f64, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct DeleteShardKeyResponse { #[prost(bool, tag = "1")] pub result: bool, + /// Time spent to process + #[prost(double, tag = "2")] + pub time: f64, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ShardKeyDescription { @@ -1744,6 +1913,7 @@ pub enum Datatype { Float32 = 1, Uint8 = 2, Float16 = 3, + Turbo4 = 4, } impl Datatype { /// String value of the enum field names used in the ProtoBuf definition. @@ -1756,6 +1926,7 @@ impl Datatype { Self::Float32 => "Float32", Self::Uint8 => "Uint8", Self::Float16 => "Float16", + Self::Turbo4 => "Turbo4", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1765,6 +1936,45 @@ impl Datatype { "Float32" => Some(Self::Float32), "Uint8" => Some(Self::Uint8), "Float16" => Some(Self::Float16), + "Turbo4" => Some(Self::Turbo4), + _ => None, + } + } +} +/// Memory placement of a component's data. +/// Data is always persisted on disk regardless of this setting; +/// it only controls how the data is held in RAM. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum Memory { + Unknown = 0, + /// Data is not pre-loaded from disk to RAM; cached with usage. + Cold = 1, + /// Data is pre-loaded into disk-cache RAM on start, but may be evicted under memory pressure. + Cached = 2, + /// Data is loaded in RAM and never evicted. + Pinned = 3, +} +impl Memory { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unknown => "MemoryUnknown", + Self::Cold => "Cold", + Self::Cached => "Cached", + Self::Pinned => "Pinned", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "MemoryUnknown" => Some(Self::Unknown), + "Cold" => Some(Self::Cold), + "Cached" => Some(Self::Cached), + "Pinned" => Some(Self::Pinned), _ => None, } } @@ -4042,7 +4252,7 @@ pub struct DenseVectorCreationConfig { /// Configuration for multi-vector search (e.g., ColBERT) #[prost(message, optional, tag = "3")] pub multivector_config: ::core::option::Option, - /// Data type of the vectors (Float32, Float16, Uint8) + /// Data type of the vectors (Float32, Float16, Uint8, Turbo4) #[prost(enumeration = "Datatype", optional, tag = "4")] pub datatype: ::core::option::Option, } @@ -4244,7 +4454,16 @@ pub struct AcornSearchParams { #[prost(double, optional, tag = "2")] pub max_selectivity: ::core::option::Option, } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +/// Population over which sparse vector IDF statistics are computed for scoring - the IDF corpus. +/// Only applicable to sparse vectors with the IDF modifier enabled. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IdfParams { + /// Filter defining the corpus: IDF statistics are computed over the points matching this filter. + /// If unset, statistics are collection-wide (global) - same as omitting `idf` entirely. + #[prost(message, optional, tag = "1")] + pub corpus: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] pub struct SearchParams { /// Params relevant to HNSW index. Size of the beam in a beam-search. /// Larger the value - more accurate the result, more time required for search. @@ -4264,6 +4483,10 @@ pub struct SearchParams { /// ACORN search params #[prost(message, optional, tag = "5")] pub acorn: ::core::option::Option, + /// Which population sparse vector IDF statistics are computed over. + /// If unset, statistics are collection-wide (global). + #[prost(message, optional, tag = "6")] + pub idf: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct SearchPoints { diff --git a/tests/builder_coverage.rs b/tests/builder_coverage.rs index 9d1a0520..434d9ead 100644 --- a/tests/builder_coverage.rs +++ b/tests/builder_coverage.rs @@ -9,8 +9,9 @@ use qdrant_client::qdrant::{ DeleteShardKeyRequestBuilder, DeleteSnapshotRequestBuilder, DeleteVectorNameRequestBuilder, DenseVectorCreationConfigBuilder, DiscoverBatchPointsBuilder, DiscoverInputBuilder, DiscoverPointsBuilder, Distance, FacetCountsBuilder, FieldType, GetPointsBuilder, - LookupLocationBuilder, MoveShardBuilder, MultiVectorComparator, MultiVectorConfigBuilder, - OrderByBuilder, ProductQuantizationBuilder, QueryBatchPointsBuilder, QueryPointGroupsBuilder, + IntegerIndexParamsBuilder, KeywordIndexParamsBuilder, LookupLocationBuilder, Memory, + MoveShardBuilder, MultiVectorComparator, MultiVectorConfigBuilder, OrderByBuilder, + ProductQuantizationBuilder, QueryBatchPointsBuilder, QueryPointGroupsBuilder, QueryPointsBuilder, RecommendBatchPointsBuilder, RecommendPointGroupsBuilder, RecommendPointsBuilder, RenameAliasBuilder, ReplicaBuilder, ReplicatePointsBuilder, ReplicateShardBuilder, RrfBuilder, ScrollPointsBuilder, SearchBatchPointsBuilder, @@ -117,4 +118,29 @@ fn builder_coverage() { .build(); RrfBuilder::new().build(); RrfBuilder::with_k(100).build(); + + // Memory placement (as of 1.19.0) + VectorParamsBuilder::new(1, Distance::Cosine) + .memory(Memory::Cold) + .build(); + ProductQuantizationBuilder::new(1) + .memory(Memory::Pinned) + .build(); + BinaryQuantizationBuilder::default() + .memory(Memory::Pinned) + .build(); + TurboQuantizationBuilder::new() + .memory(Memory::Pinned) + .build(); + KeywordIndexParamsBuilder::default() + .prefix(true) + .memory(Memory::Cached) + .build(); + IntegerIndexParamsBuilder::new(true, true) + .memory(Memory::Cached) + .build(); + TextIndexParamsBuilder::new(TokenizerType::Word) + .disabled_stemmer() + .memory(Memory::Cached) + .build(); } diff --git a/tests/snippet_tests/mod.rs b/tests/snippet_tests/mod.rs index 7dec3220..649b396c 100644 --- a/tests/snippet_tests/mod.rs +++ b/tests/snippet_tests/mod.rs @@ -5,13 +5,17 @@ mod test_config_headers; mod test_count_points; mod test_create_collection; mod test_create_collection_with_bq; +mod test_create_collection_with_memory; mod test_create_collection_with_metadata; +mod test_create_collection_with_turbo4_datatype; mod test_create_collection_with_turbo_quantization; mod test_create_field_index; mod test_create_full_snapshot; +mod test_create_keyword_index_with_prefix; mod test_create_shard_key; mod test_create_snapshot; mod test_create_text_index; +mod test_create_text_index_without_stemming; mod test_create_vector_name_dense; mod test_create_vector_name_sparse; mod test_delete_collection; @@ -41,11 +45,14 @@ mod test_query_image; mod test_query_points; mod test_query_points_groups; mod test_query_points_relevance_feedback; +mod test_query_points_with_idf_corpus; mod test_recommend_batch_points; mod test_recommend_point_groups; mod test_recommend_points; mod test_replicate_points; mod test_scroll_points; +mod test_scroll_points_with_prefix_match; +mod test_scroll_points_with_slice; mod test_scroll_points_with_vectors; mod test_search_batch_points; mod test_search_matrix_offsets; @@ -55,6 +62,7 @@ mod test_search_points; mod test_set_payload; mod test_update_aliases; mod test_update_collection; +mod test_update_collection_memory; mod test_update_collection_metadata; mod test_update_vectors; mod test_upsert_document; diff --git a/tests/snippet_tests/test_create_collection_with_memory.rs b/tests/snippet_tests/test_create_collection_with_memory.rs new file mode 100644 index 00000000..277fc730 --- /dev/null +++ b/tests/snippet_tests/test_create_collection_with_memory.rs @@ -0,0 +1,36 @@ + +#[tokio::test] +async fn test_create_collection_with_memory() { + async fn create_collection_with_memory() -> Result<(), Box> { + use qdrant_client::qdrant::{ + CreateCollectionBuilder, Distance, HnswConfigDiffBuilder, Memory, + PayloadStorageParams, ScalarQuantizationBuilder, VectorParamsBuilder, + }; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + client + .create_collection( + CreateCollectionBuilder::new("{collection_name}") + .vectors_config( + VectorParamsBuilder::new(1536, Distance::Cosine) + // Keep the original vectors on disk, cached with usage + .memory(Memory::Cold), + ) + .hnsw_config( + // Pre-load the HNSW graph into disk-cache RAM on start + HnswConfigDiffBuilder::default().memory(Memory::Cached), + ) + .quantization_config( + // Keep quantized vectors in RAM and never evict them + ScalarQuantizationBuilder::default().memory(Memory::Pinned), + ) + // Serve the payload from disk + .payload(PayloadStorageParams::from(Memory::Cold)), + ) + .await?; + Ok(()) + } + let _ = create_collection_with_memory().await; +} diff --git a/tests/snippet_tests/test_create_collection_with_turbo4_datatype.rs b/tests/snippet_tests/test_create_collection_with_turbo4_datatype.rs new file mode 100644 index 00000000..51298a1c --- /dev/null +++ b/tests/snippet_tests/test_create_collection_with_turbo4_datatype.rs @@ -0,0 +1,23 @@ + +#[tokio::test] +async fn test_create_collection_with_turbo4_datatype() { + async fn create_collection_with_turbo4_datatype() -> Result<(), Box> { + use qdrant_client::qdrant::{ + CreateCollectionBuilder, Datatype, Distance, VectorParamsBuilder, + }; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + client + .create_collection( + CreateCollectionBuilder::new("{collection_name}").vectors_config( + VectorParamsBuilder::new(1536, Distance::Cosine) + .datatype(Datatype::Turbo4), + ), + ) + .await?; + Ok(()) + } + let _ = create_collection_with_turbo4_datatype().await; +} diff --git a/tests/snippet_tests/test_create_collection_with_turbo_quantization.rs b/tests/snippet_tests/test_create_collection_with_turbo_quantization.rs index 2580dc20..1f104a5b 100644 --- a/tests/snippet_tests/test_create_collection_with_turbo_quantization.rs +++ b/tests/snippet_tests/test_create_collection_with_turbo_quantization.rs @@ -3,7 +3,7 @@ async fn test_create_collection_with_turbo_quantization() { async fn create_collection_with_turbo_quantization() -> Result<(), Box> { use qdrant_client::qdrant::{ - CreateCollectionBuilder, Distance, TurboQuantBitSize, TurboQuantizationBuilder, + CreateCollectionBuilder, Distance, Memory, TurboQuantBitSize, TurboQuantizationBuilder, VectorParamsBuilder, }; use qdrant_client::Qdrant; @@ -17,7 +17,7 @@ async fn test_create_collection_with_turbo_quantization() { .quantization_config( TurboQuantizationBuilder::new() .bits(TurboQuantBitSize::Bits2) - .always_ram(true), + .memory(Memory::Pinned), ), ) .await?; diff --git a/tests/snippet_tests/test_create_keyword_index_with_prefix.rs b/tests/snippet_tests/test_create_keyword_index_with_prefix.rs new file mode 100644 index 00000000..8b78b186 --- /dev/null +++ b/tests/snippet_tests/test_create_keyword_index_with_prefix.rs @@ -0,0 +1,29 @@ + +#[tokio::test] +async fn test_create_keyword_index_with_prefix() { + async fn create_keyword_index_with_prefix() -> Result<(), Box> { + use qdrant_client::qdrant::{ + CreateFieldIndexCollectionBuilder, FieldType, KeywordIndexParamsBuilder, Memory, + }; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + let keyword_index_params = KeywordIndexParamsBuilder::default() + // Allow `Condition::matches_prefix` on this field + .prefix(true) + .memory(Memory::Cached); + + client + .create_field_index( + CreateFieldIndexCollectionBuilder::new( + "{collection_name}", + "{field_name}", + FieldType::Keyword, + ).field_index_params(keyword_index_params.build()), + ) + .await?; + Ok(()) + } + let _ = create_keyword_index_with_prefix().await; +} diff --git a/tests/snippet_tests/test_create_text_index_without_stemming.rs b/tests/snippet_tests/test_create_text_index_without_stemming.rs new file mode 100644 index 00000000..2f7b6e75 --- /dev/null +++ b/tests/snippet_tests/test_create_text_index_without_stemming.rs @@ -0,0 +1,33 @@ + +#[tokio::test] +async fn test_create_text_index_without_stemming() { + async fn create_text_index_without_stemming() -> Result<(), Box> { + use qdrant_client::qdrant::{ + CreateFieldIndexCollectionBuilder, + FieldType, + Memory, + TextIndexParamsBuilder, + TokenizerType, + }; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + let text_index_params = TextIndexParamsBuilder::new(TokenizerType::Word) + // Explicitly turn stemming off, overriding the language default + .disabled_stemmer() + .memory(Memory::Cold); + + client + .create_field_index( + CreateFieldIndexCollectionBuilder::new( + "{collection_name}", + "{field_name}", + FieldType::Text, + ).field_index_params(text_index_params.build()), + ) + .await?; + Ok(()) + } + let _ = create_text_index_without_stemming().await; +} diff --git a/tests/snippet_tests/test_query_points_with_idf_corpus.rs b/tests/snippet_tests/test_query_points_with_idf_corpus.rs new file mode 100644 index 00000000..2e8dec8d --- /dev/null +++ b/tests/snippet_tests/test_query_points_with_idf_corpus.rs @@ -0,0 +1,32 @@ + +#[tokio::test] +async fn test_query_points_with_idf_corpus() { + async fn query_points_with_idf_corpus() -> Result<(), Box> { + use qdrant_client::qdrant::{ + Condition, Filter, IdfParams, QueryPointsBuilder, SearchParamsBuilder, + }; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + // Compute IDF statistics over the points of a single tenant instead of + // the whole collection. Only applies to sparse vectors with the IDF modifier. + client + .query( + QueryPointsBuilder::new("{collection_name}") + .query(vec![(1, 0.22), (42, 0.8)]) + .using("sparse") + .filter(Filter::must([Condition::matches( + "tenant_id", + "tenant_1".to_string(), + )])) + .params(SearchParamsBuilder::default().idf(IdfParams::from( + Filter::must([Condition::matches("tenant_id", "tenant_1".to_string())]), + ))) + .limit(10u64), + ) + .await?; + Ok(()) + } + let _ = query_points_with_idf_corpus().await; +} diff --git a/tests/snippet_tests/test_scroll_points_with_prefix_match.rs b/tests/snippet_tests/test_scroll_points_with_prefix_match.rs new file mode 100644 index 00000000..12d5225b --- /dev/null +++ b/tests/snippet_tests/test_scroll_points_with_prefix_match.rs @@ -0,0 +1,21 @@ + +#[tokio::test] +async fn test_scroll_points_with_prefix_match() { + async fn scroll_points_with_prefix_match() -> Result<(), Box> { + use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder}; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + // Requires the keyword index of the field to be created with prefix matching enabled + client + .scroll( + ScrollPointsBuilder::new("{collection_name}") + .filter(Filter::must([Condition::matches_prefix("city", "Ber")])) + .limit(10), + ) + .await?; + Ok(()) + } + let _ = scroll_points_with_prefix_match().await; +} diff --git a/tests/snippet_tests/test_scroll_points_with_slice.rs b/tests/snippet_tests/test_scroll_points_with_slice.rs new file mode 100644 index 00000000..2f14f0ad --- /dev/null +++ b/tests/snippet_tests/test_scroll_points_with_slice.rs @@ -0,0 +1,25 @@ + +#[tokio::test] +async fn test_scroll_points_with_slice() { + async fn scroll_points_with_slice() -> Result<(), Box> { + use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder}; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + // Split the id space into 4 disjoint slices, so they can be scrolled in parallel + let total_slices = 4; + + for slice in 0..total_slices { + client + .scroll( + ScrollPointsBuilder::new("{collection_name}") + .filter(Filter::must([Condition::slice(total_slices, slice)])) + .limit(10), + ) + .await?; + } + Ok(()) + } + let _ = scroll_points_with_slice().await; +} diff --git a/tests/snippet_tests/test_update_collection_memory.rs b/tests/snippet_tests/test_update_collection_memory.rs new file mode 100644 index 00000000..9e390969 --- /dev/null +++ b/tests/snippet_tests/test_update_collection_memory.rs @@ -0,0 +1,36 @@ + +#[tokio::test] +async fn test_update_collection_memory() { + async fn update_collection_memory() -> Result<(), Box> { + use qdrant_client::qdrant::{ + vectors_config_diff, CollectionParamsDiffBuilder, Memory, PayloadStorageParams, + StrictModeConfigBuilder, UpdateCollectionBuilder, VectorParamsDiffBuilder, + }; + use qdrant_client::Qdrant; + + let client = Qdrant::from_url("http://localhost:6334").build()?; + + client + .update_collection( + UpdateCollectionBuilder::new("{collection_name}") + // Move the payload storage into RAM + .params( + CollectionParamsDiffBuilder::default() + .payload(PayloadStorageParams::from(Memory::Cached)), + ) + // Move the original vectors to disk + .vectors_config(vectors_config_diff::Config::from( + VectorParamsDiffBuilder::default().memory(Memory::Cold), + )) + // Reject updates once the storage filesystem is 90% full + .strict_mode_config( + StrictModeConfigBuilder::default() + .enabled(true) + .max_disk_usage_percent(90), + ), + ) + .await?; + Ok(()) + } + let _ = update_collection_memory().await; +} From 56877632869e9c5ca1c007812a339ec51aada626 Mon Sep 17 00:00:00 2001 From: generall Date: Sat, 25 Jul 2026 12:46:40 +0200 Subject: [PATCH 2/3] Keep superseded setters warning-free for 1.18 upgrades The `#[deprecated]` attributes on `on_disk` / `always_ram` / `on_disk_payload` turn into hard errors for any downstream crate that builds with `#![deny(warnings)]` or `-D warnings` (as this repo's own CI does), which made a 1.18 -> 1.19 bump source-breaking for ordinary builder-based code. Replace them with doc-comment notes pointing at `memory` / `payload`, matching the convention already used for the 1.16 deprecations in `tests/protos.rs::configure_deprecations`. Verified by compiling the 1.18 release's own snippet suite and builder-coverage test verbatim against this branch: zero errors, zero warnings. Co-Authored-By: Claude Opus 5 (1M context) --- src/builders/binary_quantization_builder.rs | 3 ++- src/builders/bool_index_params_builder.rs | 3 ++- src/builders/collection_params_diff_builder.rs | 3 ++- src/builders/create_collection_builder.rs | 3 ++- src/builders/datetime_index_params_builder.rs | 3 ++- src/builders/float_index_params_builder.rs | 3 ++- src/builders/geo_index_params_builder.rs | 3 ++- src/builders/hnsw_config_diff_builder.rs | 3 ++- src/builders/integer_index_params_builder.rs | 3 ++- src/builders/keyword_index_params_builder.rs | 3 ++- src/builders/product_quantization_builder.rs | 3 ++- src/builders/scalar_quantization_builder.rs | 3 ++- src/builders/sparse_index_config_builder.rs | 3 ++- src/builders/text_index_params_builder.rs | 3 ++- src/builders/turbo_quantization_builder.rs | 3 ++- src/builders/uuid_index_params_builder.rs | 3 ++- src/builders/vector_params_builder.rs | 3 ++- src/builders/vector_params_diff_builder.rs | 3 ++- 18 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/builders/binary_quantization_builder.rs b/src/builders/binary_quantization_builder.rs index 29e78edb..4c43b52b 100644 --- a/src/builders/binary_quantization_builder.rs +++ b/src/builders/binary_quantization_builder.rs @@ -13,7 +13,8 @@ pub struct BinaryQuantizationBuilder { impl BinaryQuantizationBuilder { /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Some(Some(value)); diff --git a/src/builders/bool_index_params_builder.rs b/src/builders/bool_index_params_builder.rs index c599a3d4..2fc715f7 100644 --- a/src/builders/bool_index_params_builder.rs +++ b/src/builders/bool_index_params_builder.rs @@ -23,7 +23,8 @@ impl BoolIndexParamsBuilder { } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/collection_params_diff_builder.rs b/src/builders/collection_params_diff_builder.rs index 1180f17c..3c16d59f 100644 --- a/src/builders/collection_params_diff_builder.rs +++ b/src/builders/collection_params_diff_builder.rs @@ -32,7 +32,8 @@ impl CollectionParamsDiffBuilder { new } /// If true - point's payload will not be stored in memory - #[deprecated(since = "1.19.0", note = "use `payload` instead")] + /// + /// Deprecated since 1.19.0, use [`payload`](Self::payload) instead. pub fn on_disk_payload(self, value: bool) -> Self { let mut new = self; new.on_disk_payload = Option::Some(Option::Some(value)); diff --git a/src/builders/create_collection_builder.rs b/src/builders/create_collection_builder.rs index 45c432a1..1780372a 100644 --- a/src/builders/create_collection_builder.rs +++ b/src/builders/create_collection_builder.rs @@ -78,7 +78,8 @@ impl CreateCollectionBuilder { new } /// If true - point's payload will not be stored in memory - #[deprecated(since = "1.19.0", note = "use `payload` instead")] + /// + /// Deprecated since 1.19.0, use [`payload`](Self::payload) instead. pub fn on_disk_payload(self, value: bool) -> Self { let mut new = self; new.on_disk_payload = Option::Some(Option::Some(value)); diff --git a/src/builders/datetime_index_params_builder.rs b/src/builders/datetime_index_params_builder.rs index 0466fee3..8a38fb39 100644 --- a/src/builders/datetime_index_params_builder.rs +++ b/src/builders/datetime_index_params_builder.rs @@ -15,7 +15,8 @@ pub struct DatetimeIndexParamsBuilder { impl DatetimeIndexParamsBuilder { /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/float_index_params_builder.rs b/src/builders/float_index_params_builder.rs index a3028eda..4b0a6038 100644 --- a/src/builders/float_index_params_builder.rs +++ b/src/builders/float_index_params_builder.rs @@ -25,7 +25,8 @@ impl FloatIndexParamsBuilder { } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/geo_index_params_builder.rs b/src/builders/geo_index_params_builder.rs index 336ca08b..aaf50394 100644 --- a/src/builders/geo_index_params_builder.rs +++ b/src/builders/geo_index_params_builder.rs @@ -23,7 +23,8 @@ impl GeoIndexParamsBuilder { } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/hnsw_config_diff_builder.rs b/src/builders/hnsw_config_diff_builder.rs index 01231a01..58057cc5 100644 --- a/src/builders/hnsw_config_diff_builder.rs +++ b/src/builders/hnsw_config_diff_builder.rs @@ -76,7 +76,8 @@ impl HnswConfigDiffBuilder { } /// /// Store HNSW index on disk. If set to false, the index will be stored in RAM. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/integer_index_params_builder.rs b/src/builders/integer_index_params_builder.rs index b1887460..df7a02d2 100644 --- a/src/builders/integer_index_params_builder.rs +++ b/src/builders/integer_index_params_builder.rs @@ -41,7 +41,8 @@ impl IntegerIndexParamsBuilder { new } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/keyword_index_params_builder.rs b/src/builders/keyword_index_params_builder.rs index b4a8667e..5778a83f 100644 --- a/src/builders/keyword_index_params_builder.rs +++ b/src/builders/keyword_index_params_builder.rs @@ -29,7 +29,8 @@ impl KeywordIndexParamsBuilder { new } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/product_quantization_builder.rs b/src/builders/product_quantization_builder.rs index e07019d4..1e38c4f7 100644 --- a/src/builders/product_quantization_builder.rs +++ b/src/builders/product_quantization_builder.rs @@ -19,7 +19,8 @@ impl ProductQuantizationBuilder { new } /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Option::Some(Option::Some(value)); diff --git a/src/builders/scalar_quantization_builder.rs b/src/builders/scalar_quantization_builder.rs index 8d8615a2..90bd5f5e 100644 --- a/src/builders/scalar_quantization_builder.rs +++ b/src/builders/scalar_quantization_builder.rs @@ -27,7 +27,8 @@ impl ScalarQuantizationBuilder { new } /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Option::Some(Option::Some(value)); diff --git a/src/builders/sparse_index_config_builder.rs b/src/builders/sparse_index_config_builder.rs index 68479ac4..c5d0cdab 100644 --- a/src/builders/sparse_index_config_builder.rs +++ b/src/builders/sparse_index_config_builder.rs @@ -29,7 +29,8 @@ impl SparseIndexConfigBuilder { } /// /// Store inverted index on disk. If set to false, the index will be stored in RAM. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/text_index_params_builder.rs b/src/builders/text_index_params_builder.rs index ba7d2552..f0289406 100644 --- a/src/builders/text_index_params_builder.rs +++ b/src/builders/text_index_params_builder.rs @@ -58,7 +58,8 @@ impl TextIndexParamsBuilder { new } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/turbo_quantization_builder.rs b/src/builders/turbo_quantization_builder.rs index d5586f11..d725d6ae 100644 --- a/src/builders/turbo_quantization_builder.rs +++ b/src/builders/turbo_quantization_builder.rs @@ -12,7 +12,8 @@ pub struct TurboQuantizationBuilder { impl TurboQuantizationBuilder { /// If true - quantized vectors always will be stored in RAM, ignoring the config of main storage - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn always_ram(self, value: bool) -> Self { let mut new = self; new.always_ram = Some(Some(value)); diff --git a/src/builders/uuid_index_params_builder.rs b/src/builders/uuid_index_params_builder.rs index 8e80002f..629cb46e 100644 --- a/src/builders/uuid_index_params_builder.rs +++ b/src/builders/uuid_index_params_builder.rs @@ -21,7 +21,8 @@ impl UuidIndexParamsBuilder { new } /// If true - store index on disk. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/vector_params_builder.rs b/src/builders/vector_params_builder.rs index c33b8e46..b7689de4 100644 --- a/src/builders/vector_params_builder.rs +++ b/src/builders/vector_params_builder.rs @@ -51,7 +51,8 @@ impl VectorParamsBuilder { new } /// If true - serve vectors from disk. If set to false, the vectors will be loaded in RAM. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); diff --git a/src/builders/vector_params_diff_builder.rs b/src/builders/vector_params_diff_builder.rs index 31b45dfc..3128dfd0 100644 --- a/src/builders/vector_params_diff_builder.rs +++ b/src/builders/vector_params_diff_builder.rs @@ -33,7 +33,8 @@ impl VectorParamsDiffBuilder { new } /// If true - serve vectors from disk. If set to false, the vectors will be loaded in RAM. - #[deprecated(since = "1.19.0", note = "use `memory` instead")] + /// + /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead. pub fn on_disk(self, value: bool) -> Self { let mut new = self; new.on_disk = Option::Some(Option::Some(value)); From 6968026913c13d3c46738196a01366cacfa21cb3 Mon Sep 17 00:00:00 2001 From: generall Date: Sat, 25 Jul 2026 13:24:49 +0200 Subject: [PATCH 3/3] Use builders for PayloadStorageParams and IdfParams `impl From for PayloadStorageParams` and `impl From for IdfParams` hard-coded the assumption that these messages have exactly one field. As soon as the proto grows a second one, a conversion from a single field reads as arbitrary, and there is no natural place to put the rest. Replace both with `PayloadStorageParamsBuilder` and `IdfParamsBuilder`, following the pattern used by the other all-optional builders. `.payload(..)` and `.idf(..)` keep their `impl Into<..>` bounds, so the builders are accepted directly. Neither `From` impl was ever released, so this is not a compatibility concern. Co-Authored-By: Claude Opus 5 (1M context) --- src/builders/idf_params_builder.rs | 63 ++++++++++++++++++ src/builders/mod.rs | 6 ++ .../payload_storage_params_builder.rs | 64 +++++++++++++++++++ src/grpc_conversions/mod.rs | 39 ++++------- .../test_create_collection_with_memory.rs | 4 +- .../test_query_points_with_idf_corpus.rs | 11 ++-- .../test_update_collection_memory.rs | 4 +- 7 files changed, 155 insertions(+), 36 deletions(-) create mode 100644 src/builders/idf_params_builder.rs create mode 100644 src/builders/payload_storage_params_builder.rs diff --git a/src/builders/idf_params_builder.rs b/src/builders/idf_params_builder.rs new file mode 100644 index 00000000..6bd5dee2 --- /dev/null +++ b/src/builders/idf_params_builder.rs @@ -0,0 +1,63 @@ +use crate::qdrant::*; + +#[must_use] +#[derive(Clone)] +pub struct IdfParamsBuilder { + /// Filter defining the corpus IDF statistics are computed over. + pub(crate) corpus: Option>, +} + +impl Default for IdfParamsBuilder { + fn default() -> Self { + Self::new() + } +} + +impl IdfParamsBuilder { + pub fn new() -> Self { + Self::create_empty() + } + + /// Filter defining the corpus: IDF statistics are computed over the points matching + /// this filter. If unset, statistics are collection-wide (global). + pub fn corpus>(self, value: VALUE) -> Self { + let mut new = self; + new.corpus = Option::Some(Option::Some(value.into())); + new + } + + fn build_inner(self) -> Result { + Ok(IdfParams { + corpus: self.corpus.unwrap_or_default(), + }) + } + /// Create an empty builder, with all fields set to `None` or `PhantomData`. + fn create_empty() -> Self { + Self { + corpus: core::default::Default::default(), + } + } +} + +impl From for IdfParams { + fn from(value: IdfParamsBuilder) -> Self { + value.build_inner().unwrap_or_else(|_| { + panic!( + "Failed to convert {0} to {1}", + "IdfParamsBuilder", "IdfParams" + ) + }) + } +} + +impl IdfParamsBuilder { + /// Builds the desired type. Can often be omitted. + pub fn build(self) -> IdfParams { + self.build_inner().unwrap_or_else(|_| { + panic!( + "Failed to build {0} into {1}", + "IdfParamsBuilder", "IdfParams" + ) + }) + } +} diff --git a/src/builders/mod.rs b/src/builders/mod.rs index e7703d61..b1cc4df2 100644 --- a/src/builders/mod.rs +++ b/src/builders/mod.rs @@ -52,6 +52,12 @@ pub use delete_collection_builder::DeleteCollectionBuilder; mod collection_params_diff_builder; pub use collection_params_diff_builder::CollectionParamsDiffBuilder; +mod payload_storage_params_builder; +pub use payload_storage_params_builder::PayloadStorageParamsBuilder; + +mod idf_params_builder; +pub use idf_params_builder::IdfParamsBuilder; + mod keyword_index_params_builder; pub use keyword_index_params_builder::KeywordIndexParamsBuilder; diff --git a/src/builders/payload_storage_params_builder.rs b/src/builders/payload_storage_params_builder.rs new file mode 100644 index 00000000..ae9b5e8f --- /dev/null +++ b/src/builders/payload_storage_params_builder.rs @@ -0,0 +1,64 @@ +use crate::qdrant::*; + +#[must_use] +#[derive(Clone)] +pub struct PayloadStorageParamsBuilder { + /// Memory placement of the payload storage. + pub(crate) memory: Option>, +} + +impl Default for PayloadStorageParamsBuilder { + fn default() -> Self { + Self::new() + } +} + +impl PayloadStorageParamsBuilder { + pub fn new() -> Self { + Self::create_empty() + } + + /// Memory placement of the payload storage. + /// Overrides the deprecated `on_disk_payload` flag if both are set. + /// [`Memory::Pinned`] is not supported for payload storage. + pub fn memory>(self, value: VALUE) -> Self { + let mut new = self; + new.memory = Option::Some(Option::Some(value.into())); + new + } + + fn build_inner(self) -> Result { + Ok(PayloadStorageParams { + memory: self.memory.unwrap_or_default(), + }) + } + /// Create an empty builder, with all fields set to `None` or `PhantomData`. + fn create_empty() -> Self { + Self { + memory: core::default::Default::default(), + } + } +} + +impl From for PayloadStorageParams { + fn from(value: PayloadStorageParamsBuilder) -> Self { + value.build_inner().unwrap_or_else(|_| { + panic!( + "Failed to convert {0} to {1}", + "PayloadStorageParamsBuilder", "PayloadStorageParams" + ) + }) + } +} + +impl PayloadStorageParamsBuilder { + /// Builds the desired type. Can often be omitted. + pub fn build(self) -> PayloadStorageParams { + self.build_inner().unwrap_or_else(|_| { + panic!( + "Failed to build {0} into {1}", + "PayloadStorageParamsBuilder", "PayloadStorageParams" + ) + }) + } +} diff --git a/src/grpc_conversions/mod.rs b/src/grpc_conversions/mod.rs index dc8552cc..7d74f7ee 100644 --- a/src/grpc_conversions/mod.rs +++ b/src/grpc_conversions/mod.rs @@ -15,18 +15,17 @@ use crate::qdrant::{ AbortShardTransfer, AbortShardTransferBuilder, AliasOperations, BinaryQuantization, BinaryQuantizationBuilder, Condition, CreateAlias, CreateShardKey, DeleteAlias, DeleteShardKey, DenseVectorCreationConfig, DenseVectorCreationConfigBuilder, Disabled, FieldCondition, Filter, - GeoLineString, GeoPoint, GroupId, HasIdCondition, IdfParams, IsEmptyCondition, IsNullCondition, - ListValue, Match, Memory, MoveShard, MoveShardBuilder, NestedCondition, PayloadExcludeSelector, - PayloadIncludeSelector, PayloadStorageParams, PointId, PointsIdsList, PointsSelector, - PointsUpdateOperation, ProductQuantization, ProductQuantizationBuilder, QuantizationConfig, - QuantizationConfigDiff, ReadConsistency, RenameAlias, Replica, ReplicateShard, - ReplicateShardBuilder, RestartTransfer, ScalarQuantization, ScalarQuantizationBuilder, - ShardKey, ShardKeySelector, SliceCondition, SparseIndexConfig, SparseVectorCreationConfig, - SparseVectorCreationConfigBuilder, SparseVectorParams, StartFrom, Struct, TargetVector, - TurboQuantization, TurboQuantizationBuilder, Value, Vector, VectorExample, VectorParams, - VectorParamsBuilder, VectorParamsDiff, VectorParamsDiffBuilder, VectorParamsDiffMap, - VectorParamsMap, VectorsConfig, VectorsConfigDiff, VectorsSelector, WithPayloadSelector, - WithVectorsSelector, + GeoLineString, GeoPoint, GroupId, HasIdCondition, IsEmptyCondition, IsNullCondition, ListValue, + Match, MoveShard, MoveShardBuilder, NestedCondition, PayloadExcludeSelector, + PayloadIncludeSelector, PointId, PointsIdsList, PointsSelector, PointsUpdateOperation, + ProductQuantization, ProductQuantizationBuilder, QuantizationConfig, QuantizationConfigDiff, + ReadConsistency, RenameAlias, Replica, ReplicateShard, ReplicateShardBuilder, RestartTransfer, + ScalarQuantization, ScalarQuantizationBuilder, ShardKey, ShardKeySelector, SliceCondition, + SparseIndexConfig, SparseVectorCreationConfig, SparseVectorCreationConfigBuilder, + SparseVectorParams, StartFrom, Struct, TargetVector, TurboQuantization, + TurboQuantizationBuilder, Value, Vector, VectorExample, VectorParams, VectorParamsBuilder, + VectorParamsDiff, VectorParamsDiffBuilder, VectorParamsDiffMap, VectorParamsMap, VectorsConfig, + VectorsConfigDiff, VectorsSelector, WithPayloadSelector, WithVectorsSelector, }; impl From> for PointsSelector { @@ -531,22 +530,6 @@ impl From for quantization_config::Quantization { } } -impl From for PayloadStorageParams { - fn from(value: Memory) -> Self { - Self { - memory: Some(value.into()), - } - } -} - -impl From for IdfParams { - fn from(value: Filter) -> Self { - Self { - corpus: Some(value), - } - } -} - impl From for points_update_operation::Operation { fn from(value: points_update_operation::PointStructList) -> Self { Self::Upsert(value) diff --git a/tests/snippet_tests/test_create_collection_with_memory.rs b/tests/snippet_tests/test_create_collection_with_memory.rs index 277fc730..972967c6 100644 --- a/tests/snippet_tests/test_create_collection_with_memory.rs +++ b/tests/snippet_tests/test_create_collection_with_memory.rs @@ -4,7 +4,7 @@ async fn test_create_collection_with_memory() { async fn create_collection_with_memory() -> Result<(), Box> { use qdrant_client::qdrant::{ CreateCollectionBuilder, Distance, HnswConfigDiffBuilder, Memory, - PayloadStorageParams, ScalarQuantizationBuilder, VectorParamsBuilder, + PayloadStorageParamsBuilder, ScalarQuantizationBuilder, VectorParamsBuilder, }; use qdrant_client::Qdrant; @@ -27,7 +27,7 @@ async fn test_create_collection_with_memory() { ScalarQuantizationBuilder::default().memory(Memory::Pinned), ) // Serve the payload from disk - .payload(PayloadStorageParams::from(Memory::Cold)), + .payload(PayloadStorageParamsBuilder::default().memory(Memory::Cold)), ) .await?; Ok(()) diff --git a/tests/snippet_tests/test_query_points_with_idf_corpus.rs b/tests/snippet_tests/test_query_points_with_idf_corpus.rs index 2e8dec8d..5efb95b8 100644 --- a/tests/snippet_tests/test_query_points_with_idf_corpus.rs +++ b/tests/snippet_tests/test_query_points_with_idf_corpus.rs @@ -3,7 +3,7 @@ async fn test_query_points_with_idf_corpus() { async fn query_points_with_idf_corpus() -> Result<(), Box> { use qdrant_client::qdrant::{ - Condition, Filter, IdfParams, QueryPointsBuilder, SearchParamsBuilder, + Condition, Filter, IdfParamsBuilder, QueryPointsBuilder, SearchParamsBuilder, }; use qdrant_client::Qdrant; @@ -20,9 +20,12 @@ async fn test_query_points_with_idf_corpus() { "tenant_id", "tenant_1".to_string(), )])) - .params(SearchParamsBuilder::default().idf(IdfParams::from( - Filter::must([Condition::matches("tenant_id", "tenant_1".to_string())]), - ))) + .params(SearchParamsBuilder::default().idf( + IdfParamsBuilder::default().corpus(Filter::must([Condition::matches( + "tenant_id", + "tenant_1".to_string(), + )])), + )) .limit(10u64), ) .await?; diff --git a/tests/snippet_tests/test_update_collection_memory.rs b/tests/snippet_tests/test_update_collection_memory.rs index 9e390969..0b74cacb 100644 --- a/tests/snippet_tests/test_update_collection_memory.rs +++ b/tests/snippet_tests/test_update_collection_memory.rs @@ -3,7 +3,7 @@ async fn test_update_collection_memory() { async fn update_collection_memory() -> Result<(), Box> { use qdrant_client::qdrant::{ - vectors_config_diff, CollectionParamsDiffBuilder, Memory, PayloadStorageParams, + vectors_config_diff, CollectionParamsDiffBuilder, Memory, PayloadStorageParamsBuilder, StrictModeConfigBuilder, UpdateCollectionBuilder, VectorParamsDiffBuilder, }; use qdrant_client::Qdrant; @@ -16,7 +16,7 @@ async fn test_update_collection_memory() { // Move the payload storage into RAM .params( CollectionParamsDiffBuilder::default() - .payload(PayloadStorageParams::from(Memory::Cached)), + .payload(PayloadStorageParamsBuilder::default().memory(Memory::Cached)), ) // Move the original vectors to disk .vectors_config(vectors_config_diff::Config::from(