Skip to main content

qdrant_edge/edge/config/
vectors.rs

1//! User-facing vector and sparse-vector parameters for the edge shard.
2//!
3//! Uses `on_disk` (bool) instead of internal `storage_type`. Per-vector quantization
4//! is supported via `EdgeVectorParams::quantization_config`; when set it overrides the
5//! global `EdgeShardConfig::quantization_config` for that vector.
6
7use crate::segment::data_types::modifier::Modifier;
8use crate::segment::index::sparse_index::sparse_index_config::{SparseIndexConfig, SparseIndexType};
9use crate::segment::types::{
10    Distance, HnswConfig, Indexes, MultiVectorConfig, QuantizationConfig, SparseVectorDataConfig,
11    SparseVectorStorageType, VectorDataConfig, VectorStorageDatatype, VectorStorageType,
12};
13use serde::{Deserialize, Serialize};
14use crate::shard::optimizers::config::DenseVectorOptimizerConfig;
15
16/// User-facing dense vector parameters.
17///
18/// Uses `on_disk: bool` instead of `storage_type`. Per-vector quantization is
19/// supported via `quantization_config` and overrides the global config when set.
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub struct EdgeVectorParams {
23    pub size: usize,
24    pub distance: Distance,
25    /// If true, vector storage is on disk (mmap); otherwise in RAM.
26    /// Default is false (RAM).
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub on_disk: Option<bool>,
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub multivector_config: Option<MultiVectorConfig>,
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    pub datatype: Option<VectorStorageDatatype>,
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub quantization_config: Option<QuantizationConfig>,
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub hnsw_config: Option<HnswConfig>,
37}
38
39impl EdgeVectorParams {
40    /// Start building [`EdgeVectorParams`] with a fluent API. The two
41    /// required fields (`size`, `distance`) are supplied here.
42    pub fn builder(size: usize, distance: Distance) -> crate::edge::builders::EdgeVectorParamsBuilder {
43        crate::edge::builders::EdgeVectorParamsBuilder::new(size, distance)
44    }
45
46    /// Build `VectorDataConfig` for segment/optimizer use, using global quantization.
47    pub fn to_plain_vector_data_config(
48        &self,
49        global_quantization: Option<&QuantizationConfig>,
50    ) -> VectorDataConfig {
51        let EdgeVectorParams {
52            size,
53            distance,
54            on_disk,
55            multivector_config,
56            datatype,
57            quantization_config,
58            hnsw_config: _, // edge does not use per-vector HNSW config
59        } = self;
60
61        let resolved_quantization_config = quantization_config.as_ref().or(global_quantization);
62        let quantization_config =
63            QuantizationConfig::for_appendable_segment(resolved_quantization_config);
64        VectorDataConfig {
65            size: *size,
66            distance: *distance,
67            storage_type: VectorStorageType::from_on_disk(on_disk.unwrap_or_default()),
68            index: Indexes::Plain {},
69            quantization_config,
70            multivector_config: *multivector_config,
71            datatype: *datatype,
72        }
73    }
74
75    pub fn to_dense_vector_optimizer_config(
76        &self,
77        global_hnsw_config: &HnswConfig,
78        global_quantization_config: Option<&QuantizationConfig>,
79    ) -> DenseVectorOptimizerConfig {
80        let EdgeVectorParams {
81            size: _,
82            distance: _,
83            on_disk,
84            multivector_config: _,
85            datatype: _,
86            quantization_config,
87            hnsw_config,
88        } = self;
89        DenseVectorOptimizerConfig {
90            on_disk: *on_disk,
91            memory: None,
92            hnsw_config: hnsw_config.unwrap_or(*global_hnsw_config),
93            quantization_config: quantization_config
94                .clone()
95                .or_else(|| global_quantization_config.cloned()),
96        }
97    }
98
99    pub fn from_vector_data_config(v: &VectorDataConfig) -> Self {
100        let VectorDataConfig {
101            size,
102            distance,
103            storage_type,
104            index,
105            quantization_config, // edge uses global only
106            multivector_config,
107            datatype,
108        } = v;
109        Self {
110            size: *size,
111            distance: *distance,
112            on_disk: Some(storage_type.is_on_disk()),
113            multivector_config: *multivector_config,
114            datatype: *datatype,
115            quantization_config: quantization_config.clone(),
116            hnsw_config: match index {
117                Indexes::Plain {} => None,
118                Indexes::Hnsw(hnsw_config) => Some(*hnsw_config),
119            },
120        }
121    }
122}
123
124/// User-facing sparse vector parameters.
125///
126/// Uses `on_disk: bool` instead of internal storage/index type enums.
127#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
128#[serde(rename_all = "snake_case")]
129pub struct EdgeSparseVectorParams {
130    #[serde(default, skip_serializing_if = "Option::is_none")]
131    pub full_scan_threshold: Option<usize>,
132    /// If true, sparse index is on disk (mmap); otherwise in RAM.
133    #[serde(default, skip_serializing_if = "Option::is_none")]
134    pub on_disk: Option<bool>,
135    #[serde(default, skip_serializing_if = "Option::is_none")]
136    pub modifier: Option<Modifier>,
137    #[serde(default, skip_serializing_if = "Option::is_none")]
138    pub datatype: Option<VectorStorageDatatype>,
139}
140
141impl EdgeSparseVectorParams {
142    /// Start building [`EdgeSparseVectorParams`] with a fluent API.
143    pub fn builder() -> crate::edge::builders::EdgeSparseVectorParamsBuilder {
144        crate::edge::builders::EdgeSparseVectorParamsBuilder::new()
145    }
146
147    pub fn to_plain_sparse_vector_data_config(&self) -> SparseVectorDataConfig {
148        let EdgeSparseVectorParams {
149            full_scan_threshold,
150            on_disk: _,
151            modifier,
152            datatype,
153        } = self;
154        SparseVectorDataConfig {
155            index: SparseIndexConfig {
156                full_scan_threshold: *full_scan_threshold,
157                index_type: SparseIndexType::default(),
158                datatype: *datatype,
159                memory: None,
160            },
161            storage_type: SparseVectorStorageType::Mmap,
162            modifier: *modifier,
163        }
164    }
165
166    pub fn to_sparse_vector_optimizer_config(
167        &self,
168    ) -> crate::shard::optimizers::config::SparseVectorOptimizerConfig {
169        let EdgeSparseVectorParams {
170            full_scan_threshold: _,
171            on_disk,
172            modifier: _,
173            datatype: _,
174        } = self;
175        crate::shard::optimizers::config::SparseVectorOptimizerConfig {
176            on_disk: *on_disk,
177            memory: None,
178        }
179    }
180
181    pub fn from_sparse_vector_data_config(s: &SparseVectorDataConfig) -> Self {
182        let SparseVectorDataConfig {
183            index,
184            storage_type: _, // edge uses on_disk from index_type
185            modifier,
186        } = s;
187        let SparseIndexConfig {
188            full_scan_threshold,
189            index_type,
190            datatype,
191            memory: _,
192        } = index;
193        Self {
194            full_scan_threshold: *full_scan_threshold,
195            on_disk: Some(index_type.is_on_disk()),
196            modifier: *modifier,
197            datatype: *datatype,
198        }
199    }
200}