Skip to main content

vecdb_core/sparse/
mod.rs

1pub mod inverted;
2pub mod tokenizer;
3
4pub use inverted::{InvertedIndex, PostingEntry, PostingList};
5pub use tokenizer::{Tokenizer, TokenizerConfig};
6
7use std::path::{Path, PathBuf};
8
9use crate::errors::Result;
10use crate::types::VectorId;
11
12// ──────────────────────────────────────────────
13// SparseIndex facade
14// ──────────────────────────────────────────────
15
16/// High-level facade over `InvertedIndex`.
17///
18/// Owns a file path and delegates all indexing/search operations to the
19/// underlying `InvertedIndex`. Persist with `save()`; reconstruct from disk
20/// with `open()`.
21pub struct SparseIndex {
22    pub index: InvertedIndex,
23    path: PathBuf,
24}
25
26impl SparseIndex {
27    /// Create a fresh empty index that will persist to `path`.
28    pub fn create(path: &Path) -> Self {
29        Self {
30            index: InvertedIndex::default(),
31            path: path.to_path_buf(),
32        }
33    }
34
35    /// Open an existing index from `path`, or create empty if file absent.
36    pub fn open(path: &Path) -> Result<Self> {
37        let index = if path.exists() {
38            InvertedIndex::load(path)?
39        } else {
40            InvertedIndex::default()
41        };
42        Ok(Self {
43            index,
44            path: path.to_path_buf(),
45        })
46    }
47
48    /// Add or update a document.
49    pub fn index_document(&mut self, id: &VectorId, text: &str) -> Result<()> {
50        self.index.index_document(id, text)
51    }
52
53    /// Remove a document. Returns `NotFound` if absent.
54    pub fn remove_document(&mut self, id: &VectorId) -> Result<()> {
55        self.index.remove_document(id)
56    }
57
58    /// Full-text BM25 search. Returns up to `k` results sorted by score desc.
59    pub fn search(&self, query: &str, k: usize) -> Result<Vec<(VectorId, f32)>> {
60        self.index.search(query, k)
61    }
62
63    /// Persist the index to its file path.
64    pub fn save(&self) -> Result<()> {
65        self.index.save(&self.path)
66    }
67
68    /// Score `query_text` against a specific set of candidate document IDs.
69    ///
70    /// Tokenizes the query internally. Returns BM25 scores only for the
71    /// provided candidates. If `candidate_ids` is empty, all documents are
72    /// scored (same as `score_all` but without a `k` truncation).
73    pub fn score(
74        &self,
75        query_text: &str,
76        candidate_ids: &[VectorId],
77    ) -> Result<Vec<(VectorId, f32)>> {
78        self.index.score_candidates(query_text, candidate_ids)
79    }
80
81    /// Score `query_text` against all indexed documents. Returns top `k`.
82    pub fn score_all(&self, query_text: &str, k: usize) -> Result<Vec<(VectorId, f32)>> {
83        self.index.search(query_text, k)
84    }
85
86    pub fn doc_count(&self) -> usize {
87        self.index.doc_count()
88    }
89}