faiss-next 0.6.0

Rust bindings for Faiss (Facebook AI Similarity Search)
Documentation
use crate::idx::Idx;

#[derive(Debug, Clone)]
pub struct SearchResult {
    pub distances: Vec<f32>,
    pub labels: Vec<Idx>,
}

impl SearchResult {
    pub fn new(distances: Vec<f32>, labels: Vec<Idx>) -> Self {
        Self { distances, labels }
    }

    pub fn len(&self) -> usize {
        self.labels.len()
    }

    pub fn is_empty(&self) -> bool {
        self.labels.is_empty()
    }

    pub fn n_queries(&self) -> usize {
        if self.labels.is_empty() {
            0
        } else {
            self.distances.len() / self.labels.len() * self.labels.len()
        }
    }

    pub fn iter(&self) -> impl Iterator<Item = (Idx, f32)> + '_ {
        self.labels
            .iter()
            .copied()
            .zip(self.distances.iter().copied())
    }

    pub fn labels(&self) -> impl Iterator<Item = Option<u64>> + '_ {
        self.labels.iter().map(|&l| l.get())
    }

    pub fn get(&self, query_idx: usize, k: usize) -> Option<(Vec<Idx>, Vec<f32>)> {
        let start = query_idx * k;
        let end = start + k;
        if end <= self.labels.len() && end <= self.distances.len() {
            Some((
                self.labels[start..end].to_vec(),
                self.distances[start..end].to_vec(),
            ))
        } else {
            None
        }
    }

    pub fn first_label(&self) -> Option<u64> {
        self.labels.first().and_then(|&l| l.get())
    }

    pub fn first_distance(&self) -> Option<f32> {
        self.distances.first().copied()
    }
}

#[derive(Debug, Clone)]
pub struct RangeSearchResult {
    pub labels: Vec<Idx>,
    pub distances: Vec<f32>,
    pub lims: Vec<usize>,
}

impl RangeSearchResult {
    pub fn new(labels: Vec<Idx>, distances: Vec<f32>, lims: Vec<usize>) -> Self {
        Self {
            labels,
            distances,
            lims,
        }
    }

    pub fn n_queries(&self) -> usize {
        self.lims.len().saturating_sub(1)
    }

    pub fn total_results(&self) -> usize {
        self.labels.len()
    }

    pub fn get(&self, query_idx: usize) -> Option<(Vec<Idx>, Vec<f32>)> {
        let start = *self.lims.get(query_idx)?;
        let end = *self.lims.get(query_idx + 1)?;
        Some((
            self.labels[start..end].to_vec(),
            self.distances[start..end].to_vec(),
        ))
    }

    pub fn iter(&self) -> RangeSearchResultIter<'_> {
        RangeSearchResultIter {
            result: self,
            query_idx: 0,
        }
    }
}

pub struct RangeSearchResultIter<'a> {
    result: &'a RangeSearchResult,
    query_idx: usize,
}

impl<'a> Iterator for RangeSearchResultIter<'a> {
    type Item = (Vec<Idx>, Vec<f32>);

    fn next(&mut self) -> Option<Self::Item> {
        let result = self.result.get(self.query_idx)?;
        self.query_idx += 1;
        Some(result)
    }
}

#[derive(Debug, Clone)]
pub struct BinarySearchResult {
    pub distances: Vec<i32>,
    pub labels: Vec<Idx>,
}

impl BinarySearchResult {
    pub fn new(distances: Vec<i32>, labels: Vec<Idx>) -> Self {
        Self { distances, labels }
    }

    pub fn len(&self) -> usize {
        self.labels.len()
    }

    pub fn is_empty(&self) -> bool {
        self.labels.is_empty()
    }

    pub fn iter(&self) -> impl Iterator<Item = (Idx, i32)> + '_ {
        self.labels
            .iter()
            .copied()
            .zip(self.distances.iter().copied())
    }

    pub fn get(&self, query_idx: usize, k: usize) -> Option<(Vec<Idx>, Vec<i32>)> {
        let start = query_idx * k;
        let end = start + k;
        if end <= self.labels.len() && end <= self.distances.len() {
            Some((
                self.labels[start..end].to_vec(),
                self.distances[start..end].to_vec(),
            ))
        } else {
            None
        }
    }
}