qdrant-client 1.20.0

Rust client for Qdrant Vector Search Engine
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
//! Public models for the Qdrant Serverless collection management API.
//!
//! **In development — do not use yet.** Part of the experimental serverless client;
//! the API may change without notice.
//!
//! These mirror the tenant-facing serverless config: unlike the regular client's
//! collection models, they deliberately expose no storage internals (quantization,
//! WAL, segments, on-disk placement, ...) — the serverless manager decides those.

use std::collections::HashMap;

/// Distance metric used to compare dense vectors.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum Distance {
    Cosine,
    Euclid,
    Dot,
    Manhattan,
}

/// How much of the original vector precision may be traded for cost.
///
/// The manager turns this into a concrete quantization / datatype choice.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum PrecisionTier {
    Low,
    Medium,
    High,
    Full,
}

/// Full-text tokenizer, mirrors Qdrant's `TokenizerType`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum Tokenizer {
    Prefix,
    Whitespace,
    Word,
    Multilingual,
}

/// Configuration of a single dense (embedding) vector.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DenseVectorConfig {
    /// Dimensionality of the embedding, e.g. 512, 1536, 3072.
    pub size: u64,
    /// Distance metric used to compare vectors.
    pub distance: Distance,
    /// Store several sub-vectors per point and compare with max-sim.
    pub multivector: bool,
    /// Precision/cost trade-off for this vector. Unset: HIGH.
    pub precision_tier: Option<PrecisionTier>,
}

impl DenseVectorConfig {
    /// Create a dense vector config with the given size and distance.
    pub fn new(size: u64, distance: Distance) -> Self {
        Self {
            size,
            distance,
            multivector: false,
            precision_tier: None,
        }
    }

    /// Enable multi-vector (late-interaction) storage.
    pub fn multivector(mut self, multivector: bool) -> Self {
        self.multivector = multivector;
        self
    }

    /// Set the precision/cost trade-off.
    pub fn precision_tier(mut self, tier: PrecisionTier) -> Self {
        self.precision_tier = Some(tier);
        self
    }
}

/// Configuration of a single sparse vector.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SparseVectorConfig {
    /// Apply the IDF modifier at query time.
    pub use_idf: bool,
    /// Precision/cost trade-off for this vector. Unset: HIGH.
    pub precision_tier: Option<PrecisionTier>,
}

impl SparseVectorConfig {
    /// Create a sparse vector config.
    pub fn new() -> Self {
        Self::default()
    }

    /// Enable IDF weighting (BM25-style).
    pub fn use_idf(mut self, use_idf: bool) -> Self {
        self.use_idf = use_idf;
        self
    }

    /// Set the precision/cost trade-off.
    pub fn precision_tier(mut self, tier: PrecisionTier) -> Self {
        self.precision_tier = Some(tier);
        self
    }
}

/// Prefix matching options for a keyword index. Presence enables prefix matching.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KeywordPrefixParams;

/// Exact match on string values, e.g. `color: "red"`.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KeywordIndex {
    /// If set, enable prefix matching (`match: { "prefix": ... }`) on this field.
    pub prefix: Option<KeywordPrefixParams>,
}

impl KeywordIndex {
    pub fn new() -> Self {
        Self::default()
    }

    /// Enable prefix matching on this keyword field.
    pub fn with_prefix(mut self) -> Self {
        self.prefix = Some(KeywordPrefixParams);
        self
    }
}

/// Exact match and/or range filters on integers. Both default to enabled.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IntegerIndex {
    pub lookup: Option<bool>,
    pub range: Option<bool>,
}

impl IntegerIndex {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn lookup(mut self, lookup: bool) -> Self {
        self.lookup = Some(lookup);
        self
    }

    pub fn range(mut self, range: bool) -> Self {
        self.range = Some(range);
        self
    }
}

/// Range filters on floating point (and integer) numbers.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FloatIndex;

/// Exact match on UUID strings; like keyword but stored compactly.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UuidIndex;

/// Range filters on RFC 3339 datetimes.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DatetimeIndex;

/// Tokens ignored by a full-text index.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StopwordsSet {
    /// Languages whose predefined stopword lists to apply (e.g. `"english"`).
    pub languages: Vec<String>,
    /// Extra stopwords to ignore, merged with the language lists.
    pub custom: Vec<String>,
}

impl StopwordsSet {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn languages(mut self, languages: impl IntoIterator<Item = impl Into<String>>) -> Self {
        self.languages = languages.into_iter().map(Into::into).collect();
        self
    }

    pub fn custom(mut self, custom: impl IntoIterator<Item = impl Into<String>>) -> Self {
        self.custom = custom.into_iter().map(Into::into).collect();
        self
    }
}

/// Snowball stemming for a full-text index.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SnowballParams {
    /// Language for the snowball algorithm, e.g. `"english"`.
    pub language: String,
}

impl SnowballParams {
    pub fn new(language: impl Into<String>) -> Self {
        Self {
            language: language.into(),
        }
    }
}

/// Stemming algorithm for a full-text index. Unset: no stemming.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum StemmingAlgorithm {
    /// Snowball stemmer for the given language.
    Snowball(SnowballParams),
    /// Explicitly disable stemming.
    Disabled,
}

/// Full-text filtering on string values.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TextIndex {
    pub tokenizer: Option<Tokenizer>,
    pub lowercase: Option<bool>,
    pub phrase_matching: Option<bool>,
    pub min_token_len: Option<u64>,
    pub max_token_len: Option<u64>,
    pub ascii_folding: Option<bool>,
    pub stopwords: Option<StopwordsSet>,
    pub stemmer: Option<StemmingAlgorithm>,
}

impl TextIndex {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn tokenizer(mut self, tokenizer: Tokenizer) -> Self {
        self.tokenizer = Some(tokenizer);
        self
    }

    pub fn lowercase(mut self, lowercase: bool) -> Self {
        self.lowercase = Some(lowercase);
        self
    }

    pub fn phrase_matching(mut self, phrase_matching: bool) -> Self {
        self.phrase_matching = Some(phrase_matching);
        self
    }

    pub fn min_token_len(mut self, min_token_len: u64) -> Self {
        self.min_token_len = Some(min_token_len);
        self
    }

    pub fn max_token_len(mut self, max_token_len: u64) -> Self {
        self.max_token_len = Some(max_token_len);
        self
    }

    pub fn ascii_folding(mut self, ascii_folding: bool) -> Self {
        self.ascii_folding = Some(ascii_folding);
        self
    }

    pub fn stopwords(mut self, stopwords: StopwordsSet) -> Self {
        self.stopwords = Some(stopwords);
        self
    }

    pub fn stemmer(mut self, stemmer: StemmingAlgorithm) -> Self {
        self.stemmer = Some(stemmer);
        self
    }
}

/// Geo radius / bounding box / polygon filters on `{lon, lat}` values.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GeoIndex;

/// Exact match on booleans.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BoolIndex;

/// One payload index. Only the kind of filter the field supports is chosen;
/// storage placement of the index is the manager's decision.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
pub enum PayloadIndex {
    Keyword(KeywordIndex),
    Integer(IntegerIndex),
    Float(FloatIndex),
    Uuid(UuidIndex),
    Datetime(DatetimeIndex),
    Text(TextIndex),
    Geo(GeoIndex),
    Bool(BoolIndex),
}

impl From<KeywordIndex> for PayloadIndex {
    fn from(value: KeywordIndex) -> Self {
        Self::Keyword(value)
    }
}

impl From<IntegerIndex> for PayloadIndex {
    fn from(value: IntegerIndex) -> Self {
        Self::Integer(value)
    }
}

impl From<FloatIndex> for PayloadIndex {
    fn from(value: FloatIndex) -> Self {
        Self::Float(value)
    }
}

impl From<UuidIndex> for PayloadIndex {
    fn from(value: UuidIndex) -> Self {
        Self::Uuid(value)
    }
}

impl From<DatetimeIndex> for PayloadIndex {
    fn from(value: DatetimeIndex) -> Self {
        Self::Datetime(value)
    }
}

impl From<TextIndex> for PayloadIndex {
    fn from(value: TextIndex) -> Self {
        Self::Text(value)
    }
}

impl From<GeoIndex> for PayloadIndex {
    fn from(value: GeoIndex) -> Self {
        Self::Geo(value)
    }
}

impl From<BoolIndex> for PayloadIndex {
    fn from(value: BoolIndex) -> Self {
        Self::Bool(value)
    }
}

/// The tenant-facing collection config.
///
/// Vector maps are keyed by vector name; the empty name `""` is the unnamed
/// default vector. Payload indexes are keyed by payload field name
/// (JSON path, e.g. `user_id` or `meta.tags`).
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CollectionConfig {
    pub dense_vectors: HashMap<String, DenseVectorConfig>,
    pub sparse_vectors: HashMap<String, SparseVectorConfig>,
    pub payload_indexes: HashMap<String, PayloadIndex>,
}

impl CollectionConfig {
    pub fn new() -> Self {
        Self::default()
    }

    /// Register a single unnamed dense vector (empty name `""`).
    pub fn dense_vector(mut self, config: DenseVectorConfig) -> Self {
        self.dense_vectors.insert(String::new(), config);
        self
    }

    /// Register a named dense vector.
    pub fn named_dense_vector(
        mut self,
        name: impl Into<String>,
        config: DenseVectorConfig,
    ) -> Self {
        self.dense_vectors.insert(name.into(), config);
        self
    }

    /// Register a single unnamed sparse vector (empty name `""`).
    pub fn sparse_vector(mut self, config: SparseVectorConfig) -> Self {
        self.sparse_vectors.insert(String::new(), config);
        self
    }

    /// Register a named sparse vector.
    pub fn named_sparse_vector(
        mut self,
        name: impl Into<String>,
        config: SparseVectorConfig,
    ) -> Self {
        self.sparse_vectors.insert(name.into(), config);
        self
    }

    /// Add a payload index for the given field path.
    pub fn payload_index(
        mut self,
        field: impl Into<String>,
        index: impl Into<PayloadIndex>,
    ) -> Self {
        self.payload_indexes.insert(field.into(), index.into());
        self
    }
}

/// Result of [`super::QdrantServerless::create_collection`].
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CreateCollectionResult {
    /// Tenant-facing name of the collection.
    pub collection_name: String,
    /// Outcome, e.g. `"created"`.
    pub result: String,
    /// Time spent to process the request, in seconds.
    pub time: f64,
}

/// Result of [`super::QdrantServerless::delete_collection`].
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DeleteCollectionResult {
    /// Whether the collection existed and was deleted.
    pub deleted: bool,
    /// Time spent to process the request, in seconds.
    pub time: f64,
}

/// A collection's configuration and stats, as returned by [`super::QdrantServerless::get_collection`].
///
/// `point_count` is eventually consistent and absent until stats have been
/// written for the collection.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CollectionInfo {
    pub exists: bool,
    pub config: Option<CollectionConfig>,
    pub point_count: Option<u64>,
    /// Time spent to process the request, in seconds.
    pub time: f64,
}

/// Request for [`super::QdrantServerless::list_collections`].
///
/// Defaults to the server page size (20, max 100). Pass `offset_token` from a
/// previous response's `next_offset_token` to fetch the next page.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ListCollections {
    /// Maximum number of collections to return. Unset: server default (20).
    pub limit: Option<u32>,
    /// Opaque token from a previous page's `next_offset_token`.
    pub offset_token: Option<String>,
}

impl ListCollections {
    /// Create an empty request (server defaults).
    pub fn new() -> Self {
        Self::default()
    }
}

/// Builder for [`ListCollections`].
#[must_use]
#[derive(Clone, Default)]
pub struct ListCollectionsBuilder {
    limit: Option<u32>,
    offset_token: Option<String>,
}

impl ListCollectionsBuilder {
    /// Create an empty builder (server defaults).
    pub fn new() -> Self {
        Self::default()
    }

    /// Maximum number of collections to return (must be 1..=100).
    pub fn limit(mut self, limit: u32) -> Self {
        self.limit = Some(limit);
        self
    }

    /// Opaque token from a previous page's `next_offset_token`.
    pub fn offset_token(mut self, offset_token: impl Into<String>) -> Self {
        self.offset_token = Some(offset_token.into());
        self
    }

    /// Build the [`ListCollections`] request.
    pub fn build(self) -> ListCollections {
        self.into()
    }
}

impl From<ListCollectionsBuilder> for ListCollections {
    fn from(builder: ListCollectionsBuilder) -> Self {
        ListCollections {
            limit: builder.limit,
            offset_token: builder.offset_token,
        }
    }
}

/// One collection in a [`super::QdrantServerless::list_collections`] listing.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CollectionSummary {
    pub collection_name: String,
    pub point_count: Option<u64>,
}

/// A page of collections returned by [`super::QdrantServerless::list_collections`].
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CollectionsList {
    pub collections: Vec<CollectionSummary>,
    /// Opaque token to pass as `offset_token` for the next page. Absent when done.
    pub next_offset_token: Option<String>,
    /// Time spent to process the request, in seconds.
    pub time: f64,
}