#![allow(dead_code)]
#![allow(clippy::cast_precision_loss)]
use super::native::{CachedSimdDistance, NativeHnsw, NativeNeighbour};
use crate::distance::DistanceMetric;
use std::path::Path;
pub struct NativeHnswInner {
inner: NativeHnsw<CachedSimdDistance>,
metric: DistanceMetric,
}
impl NativeHnswInner {
pub fn new(
metric: DistanceMetric,
max_connections: usize,
max_elements: usize,
ef_construction: usize,
dimension: usize,
) -> crate::error::Result<Self> {
let distance = CachedSimdDistance::new(metric, dimension);
let inner = if dimension > 0 {
NativeHnsw::new_with_dimension(
distance,
max_connections,
ef_construction,
max_elements,
dimension,
)?
} else {
NativeHnsw::new(distance, max_connections, ef_construction, max_elements)
};
Ok(Self { inner, metric })
}
#[inline]
#[must_use]
pub fn search(&self, query: &[f32], k: usize, ef_search: usize) -> Vec<NativeNeighbour> {
self.inner.search_neighbours(query, k, ef_search)
}
pub fn insert(&self, data: (&[f32], usize)) -> crate::error::Result<usize> {
let (vector, expected_idx) = data;
let assigned_id = self.inner.insert(vector)?;
if assigned_id != expected_idx {
tracing::warn!(
"NativeHnsw node_id mismatch: expected {expected_idx}, got {assigned_id} \
— mapping may be desynchronised under concurrent inserts"
);
}
Ok(assigned_id)
}
pub fn parallel_insert(&self, data: &[(&[f32], usize)]) -> crate::error::Result<()> {
self.inner.parallel_insert(data)
}
pub fn set_searching_mode(&mut self, mode: bool) {
self.inner.set_searching_mode(mode);
}
pub fn file_dump(&self, path: &Path, basename: &str) -> std::io::Result<()> {
self.inner.file_dump(path, basename)
}
pub fn file_load(
path: &Path,
basename: &str,
metric: DistanceMetric,
dimension: usize,
) -> std::io::Result<Self> {
let distance = CachedSimdDistance::new(metric, dimension);
let inner = NativeHnsw::file_load(path, basename, distance)?;
Ok(Self { inner, metric })
}
#[inline]
#[must_use]
pub fn transform_score(&self, raw_distance: f32) -> f32 {
self.inner.transform_score(raw_distance)
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.inner.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
#[must_use]
pub fn metric(&self) -> DistanceMetric {
self.metric
}
#[inline]
#[must_use]
pub fn compute_distance(&self, a: &[f32], b: &[f32]) -> f32 {
self.inner.compute_distance(a, b)
}
#[inline]
pub fn with_contiguous_vectors<R: Default>(
&self,
f: impl FnOnce(&crate::perf_optimizations::ContiguousVectors) -> R,
) -> R {
self.inner.with_vectors_read(f)
}
}
unsafe impl Send for NativeHnswInner {}
unsafe impl Sync for NativeHnswInner {}