#![allow(deprecated)]
use std::collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::segment::types::{
Distance, HnswConfig, Indexes, PayloadStorageType, QuantizationConfig, SegmentConfig,
SegmentState, SeqNumberType, VectorDataConfig, VectorNameBuf, VectorStorageType,
};
#[derive(Default, Debug, Deserialize, Serialize, JsonSchema, Clone)]
#[serde(rename_all = "snake_case")]
#[deprecated = "use SegmentConfig instead"]
pub struct SegmentConfigV5 {
pub vector_data: HashMap<VectorNameBuf, VectorDataConfigV5>,
pub index: Indexes,
pub storage_type: StorageTypeV5,
#[serde(default)]
pub payload_storage_type: Option<PayloadStorageType>,
#[serde(default)]
pub quantization_config: Option<QuantizationConfig>,
}
impl From<SegmentConfigV5> for SegmentConfig {
fn from(old_segment: SegmentConfigV5) -> Self {
let SegmentConfigV5 {
vector_data,
index,
storage_type,
payload_storage_type,
quantization_config,
} = old_segment;
let vector_data = vector_data
.into_iter()
.map(|(vector_name, old_data)| {
let VectorDataConfigV5 {
size,
distance,
hnsw_config,
quantization_config: vec_quantization_config,
on_disk,
} = old_data;
let new_data = VectorDataConfig {
size,
distance,
index: match hnsw_config {
Some(hnsw_config) => Indexes::Hnsw(hnsw_config),
None => index.clone(),
},
quantization_config: quantization_config.as_ref().and(vec_quantization_config),
storage_type: if on_disk == Some(true) {
VectorStorageType::Mmap
} else {
storage_type.into()
},
multivector_config: None,
datatype: None,
};
(vector_name, new_data)
})
.collect();
let default_storage_type = PayloadStorageType::Mmap;
SegmentConfig {
vector_data,
sparse_vector_data: Default::default(),
payload_storage_type: payload_storage_type.unwrap_or(default_storage_type),
}
}
}
#[derive(Default, Debug, Deserialize, Serialize, JsonSchema, Copy, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type", content = "options")]
#[deprecated]
pub enum StorageTypeV5 {
#[default]
InMemory,
Mmap,
}
impl From<StorageTypeV5> for VectorStorageType {
fn from(old: StorageTypeV5) -> Self {
match old {
StorageTypeV5::InMemory => Self::Memory,
StorageTypeV5::Mmap => Self::Mmap,
}
}
}
#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone)]
#[serde(rename_all = "snake_case")]
#[deprecated = "use VectorDataConfig instead"]
pub struct VectorDataConfigV5 {
pub size: usize,
pub distance: Distance,
#[serde(default)]
pub hnsw_config: Option<HnswConfig>,
#[serde(default)]
pub quantization_config: Option<QuantizationConfig>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub on_disk: Option<bool>,
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "snake_case")]
#[deprecated = "use SegmentState instead"]
pub struct SegmentStateV5 {
pub version: Option<SeqNumberType>,
pub config: SegmentConfigV5,
}
impl From<SegmentStateV5> for SegmentState {
fn from(old: SegmentStateV5) -> Self {
let SegmentStateV5 { version, config } = old;
Self {
initial_version: None,
version,
config: config.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::segment::types::{ScalarQuantization, ScalarQuantizationConfig};
#[test]
fn convert_from_v5_to_newest() {
let old_segment = SegmentConfigV5 {
vector_data: vec![
(
"vec1".into(),
VectorDataConfigV5 {
size: 10,
distance: Distance::Dot,
hnsw_config: Some(HnswConfig {
memory: None,
m: 20,
ef_construct: 100,
full_scan_threshold: 10000,
max_indexing_threads: 0,
on_disk: None,
payload_m: Some(10),
inline_storage: None,
}),
quantization_config: None,
on_disk: None,
},
),
(
"vec2".into(),
VectorDataConfigV5 {
size: 10,
distance: Distance::Dot,
hnsw_config: None,
quantization_config: Some(QuantizationConfig::Scalar(ScalarQuantization {
scalar: ScalarQuantizationConfig {
memory: None,
r#type: Default::default(),
quantile: Some(0.99),
always_ram: Some(true),
},
})),
on_disk: None,
},
),
]
.into_iter()
.collect(),
index: Indexes::Hnsw(HnswConfig {
memory: None,
m: 25,
ef_construct: 120,
full_scan_threshold: 10000,
max_indexing_threads: 0,
on_disk: None,
payload_m: None,
inline_storage: None,
}),
storage_type: StorageTypeV5::InMemory,
payload_storage_type: None,
quantization_config: None,
};
let new_segment: SegmentConfig = old_segment.into();
eprintln!("new = {new_segment:#?}");
match &new_segment.vector_data.get("vec1").unwrap().index {
Indexes::Plain { .. } => panic!("expected HNSW index"),
Indexes::Hnsw(hnsw) => {
assert_eq!(hnsw.m, 20);
}
}
match &new_segment.vector_data.get("vec2").unwrap().index {
Indexes::Plain { .. } => panic!("expected HNSW index"),
Indexes::Hnsw(hnsw) => {
assert_eq!(hnsw.m, 25);
}
}
if new_segment
.vector_data
.get("vec1")
.unwrap()
.quantization_config
.is_some()
{
panic!("expected no quantization");
}
}
#[test]
fn convert_from_v5_to_newest_2() {
let old_segment = SegmentConfigV5 {
vector_data: vec![
(
"vec1".into(),
VectorDataConfigV5 {
size: 10,
distance: Distance::Dot,
hnsw_config: None,
quantization_config: None,
on_disk: None,
},
),
(
"vec2".into(),
VectorDataConfigV5 {
size: 10,
distance: Distance::Dot,
hnsw_config: None,
quantization_config: Some(QuantizationConfig::Scalar(ScalarQuantization {
scalar: ScalarQuantizationConfig {
memory: None,
r#type: Default::default(),
quantile: Some(0.99),
always_ram: Some(true),
},
})),
on_disk: None,
},
),
]
.into_iter()
.collect(),
index: Indexes::Hnsw(HnswConfig {
memory: None,
m: 25,
ef_construct: 120,
full_scan_threshold: 10000,
max_indexing_threads: 0,
on_disk: None,
payload_m: None,
inline_storage: None,
}),
storage_type: StorageTypeV5::InMemory,
payload_storage_type: None,
quantization_config: Some(QuantizationConfig::Scalar(ScalarQuantization {
scalar: ScalarQuantizationConfig {
memory: None,
r#type: Default::default(),
quantile: Some(0.95),
always_ram: Some(true),
},
})),
};
let new_segment: SegmentConfig = old_segment.into();
eprintln!("new = {new_segment:#?}");
if new_segment
.vector_data
.get("vec1")
.unwrap()
.quantization_config
.is_some()
{
panic!("expected no quantization");
}
match &new_segment
.vector_data
.get("vec2")
.unwrap()
.quantization_config
{
Some(q) => match q {
QuantizationConfig::Scalar(scalar) => {
assert_eq!(scalar.scalar.quantile, Some(0.99));
}
QuantizationConfig::Product(_) => {
panic!("expected scalar quantization")
}
QuantizationConfig::Binary(_) => {
panic!("expected scalar quantization")
}
QuantizationConfig::Turbo(_) => {
panic!("expected scalar quantization")
}
},
_ => {
panic!("expected quantization")
}
}
}
}