use std::collections::HashMap;
use std::num::NonZeroUsize;
use crate::segment::common::BYTES_IN_KB;
use crate::segment::data_types::modifier::Modifier;
use crate::segment::index::sparse_index::sparse_index_config::{SparseIndexConfig, SparseIndexType};
use crate::segment::types::{
Distance, HnswConfig, Indexes, MultiVectorConfig, PayloadStorageType, QuantizationConfig,
SegmentConfig, SparseVectorDataConfig, SparseVectorStorageType, VectorDataConfig,
VectorNameBuf, VectorStorageDatatype, VectorStorageType,
};
pub const TEMP_SEGMENTS_PATH: &str = "temp_segments";
pub const DEFAULT_MAX_SEGMENT_PER_CPU_KB: usize = 256_000;
pub const DEFAULT_INDEXING_THRESHOLD_KB: usize = 10_000;
pub const DEFAULT_DELETED_THRESHOLD: f64 = 0.2;
pub const DEFAULT_VACUUM_MIN_VECTOR_NUMBER: usize = 1000;
#[derive(Debug, Clone, PartialEq)]
pub struct DenseVectorOptimizerConfig {
pub on_disk: Option<bool>,
pub hnsw_config: HnswConfig,
pub quantization_config: Option<QuantizationConfig>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SparseVectorOptimizerConfig {
pub on_disk: Option<bool>,
}
#[derive(Debug, Clone)]
pub struct SegmentOptimizerConfig {
pub payload_storage_type: PayloadStorageType,
pub plain_dense_vector_config: HashMap<VectorNameBuf, VectorDataConfig>,
pub plain_sparse_vector_config: HashMap<VectorNameBuf, SparseVectorDataConfig>,
pub dense_vector: HashMap<VectorNameBuf, DenseVectorOptimizerConfig>,
pub sparse_vector: HashMap<VectorNameBuf, SparseVectorOptimizerConfig>,
}
impl SegmentOptimizerConfig {
pub fn plain_segment_config(&self) -> SegmentConfig {
SegmentConfig {
vector_data: self.plain_dense_vector_config.clone(),
sparse_vector_data: self.plain_sparse_vector_config.clone(),
payload_storage_type: self.payload_storage_type,
}
}
pub fn new(
payload_storage_type: PayloadStorageType,
dense_vectors: HashMap<VectorNameBuf, DenseVectorOptimizerInput>,
sparse_vectors: HashMap<VectorNameBuf, SparseVectorOptimizerInput>,
) -> SegmentOptimizerConfig {
let (mut plain_dense_vector_config, mut dense_vector) = (HashMap::new(), HashMap::new());
for (name, input) in dense_vectors {
let DenseVectorOptimizerInput {
size,
distance,
on_disk,
hnsw_config,
quantization_config,
multivector_config,
datatype,
} = input;
plain_dense_vector_config.insert(
name.clone(),
VectorDataConfig {
size,
distance,
index: Indexes::Plain {},
storage_type: VectorStorageType::from_on_disk(on_disk.unwrap_or_default()),
quantization_config: QuantizationConfig::for_appendable_segment(
quantization_config.as_ref(),
),
multivector_config,
datatype,
},
);
dense_vector.insert(
name,
DenseVectorOptimizerConfig {
on_disk,
hnsw_config,
quantization_config,
},
);
}
let (mut plain_sparse_vector_config, mut sparse_vector) = (HashMap::new(), HashMap::new());
for (name, input) in sparse_vectors {
let SparseVectorOptimizerInput {
on_disk,
full_scan_threshold,
index_datatype,
storage_type,
modifier,
} = input;
plain_sparse_vector_config.insert(
name.clone(),
SparseVectorDataConfig {
index: SparseIndexConfig {
full_scan_threshold,
index_type: SparseIndexType::MutableRam,
datatype: index_datatype,
},
storage_type,
modifier,
},
);
sparse_vector.insert(name, SparseVectorOptimizerConfig { on_disk });
}
SegmentOptimizerConfig {
payload_storage_type,
plain_dense_vector_config,
plain_sparse_vector_config,
dense_vector,
sparse_vector,
}
}
}
#[derive(Debug, Clone)]
pub struct DenseVectorOptimizerInput {
pub size: usize,
pub distance: Distance,
pub on_disk: Option<bool>,
pub hnsw_config: HnswConfig,
pub quantization_config: Option<QuantizationConfig>,
pub multivector_config: Option<MultiVectorConfig>,
pub datatype: Option<VectorStorageDatatype>,
}
#[derive(Debug, Clone)]
pub struct SparseVectorOptimizerInput {
pub on_disk: Option<bool>,
pub full_scan_threshold: Option<usize>,
pub index_datatype: Option<VectorStorageDatatype>,
pub storage_type: SparseVectorStorageType,
pub modifier: Option<Modifier>,
}
pub fn default_segment_number() -> usize {
let expected_segments = crate::common::cpu::get_num_cpus() / 2;
expected_segments.clamp(2, 8)
}
pub fn get_number_segments(requested_segment_number: usize) -> usize {
if requested_segment_number == 0 {
default_segment_number()
} else {
requested_segment_number
}
}
pub fn get_indexing_threshold_kb(indexing_threshold: Option<usize>) -> usize {
match indexing_threshold {
None => DEFAULT_INDEXING_THRESHOLD_KB,
Some(0) => usize::MAX,
Some(custom) => custom,
}
}
pub fn get_max_segment_size_kb(
max_segment_size: Option<usize>,
num_indexing_threads: usize,
) -> usize {
if let Some(max) = max_segment_size {
max
} else {
num_indexing_threads.saturating_mul(DEFAULT_MAX_SEGMENT_PER_CPU_KB)
}
}
pub fn get_deferred_points_threshold_bytes(
prevent_unoptimized: Option<bool>,
indexing_threshold_kb: usize,
) -> Option<NonZeroUsize> {
(prevent_unoptimized == Some(true))
.then(|| indexing_threshold_kb.saturating_mul(BYTES_IN_KB))
.and_then(NonZeroUsize::new)
}