use super::graph_build::build_graphs;
use super::{Graph, RoutingIndex, VectorIndex};
use crate::config::IndexConfig;
use crate::error::SearchError;
use crate::vector::VectorStore;
use std::sync::Arc;
impl VectorIndex {
pub fn build(config: IndexConfig, vectors: &[(u64, &[f32])]) -> Result<Self, SearchError> {
config.validate()?;
let vectors = Arc::new(VectorStore::build(
config.dimensions,
config.metric,
vectors,
)?);
let graphs = build_graphs(&vectors, &config)?;
let routing = RoutingIndex::build(&vectors)?;
Ok(Self {
config,
vectors,
graphs,
routing,
})
}
pub(crate) fn from_parts(
config: IndexConfig,
vectors: VectorStore,
graphs: Vec<Graph>,
routing: RoutingIndex,
) -> Result<Self, SearchError> {
config.validate()?;
if graphs.len() != config.replicas {
return Err(SearchError::CorruptSnapshot(
"graph replica count does not match index config",
));
}
if graphs
.iter()
.any(|graph| graph.nodes.len() != vectors.len())
{
return Err(SearchError::CorruptSnapshot(
"graph node count does not match vector count",
));
}
Ok(Self {
config,
vectors: Arc::new(vectors),
graphs,
routing,
})
}
#[must_use]
pub fn len(&self) -> usize {
self.vectors.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.vectors.is_empty()
}
#[must_use]
pub const fn dimensions(&self) -> usize {
self.config.dimensions
}
#[must_use]
pub fn config(&self) -> &IndexConfig {
&self.config
}
#[must_use]
pub fn keys(&self) -> impl ExactSizeIterator<Item = u64> + '_ {
self.vectors.keys().iter().copied()
}
#[must_use]
pub fn vector(&self, key: u64) -> Option<&[f32]> {
self.vectors
.find_index(key)
.map(|index| self.vectors.vector(index))
}
pub(crate) fn vectors(&self) -> &VectorStore {
&self.vectors
}
pub(crate) fn graphs(&self) -> &[Graph] {
&self.graphs
}
pub(crate) fn routing(&self) -> &RoutingIndex {
&self.routing
}
#[must_use]
pub fn estimated_memory_bytes(&self) -> usize {
self.vectors
.estimated_bytes()
.saturating_add(self.graphs.iter().map(Graph::estimated_bytes).sum())
.saturating_add(self.routing.estimated_bytes())
}
}