feox_vector/lib.rs
1//! # FeOx Vector
2//!
3//! An embedded vector store for Rust, built on [FeOxDB](https://crates.io/crates/feoxdb)
4//! and [feox-ann](https://crates.io/crates/feox-ann). Exact and approximate cosine
5//! similarity search with metadata filtering, in your process, with no server to run.
6//!
7//! ## Highlights
8//!
9//! - **Exact and ANN queries**: brute-force scans for small or heavily filtered
10//! collections, HNSW via `feox-ann` for large ones. Selectable per query.
11//! - **Metadata filtering**: `$eq`, `$in`, `$nin` operators compiled against an
12//! inverted facet index. Small filtered candidate sets are re-ranked exactly
13//! instead of traversing the ANN graph, so selective filters return exact
14//! results.
15//! - **Lock-free index refresh**: ANN snapshots are published through `arc-swap`.
16//! Writes mark a scope dirty and a background thread rebuilds without blocking
17//! queries. Queries fall back to exact scans until a fresh snapshot is ready.
18//! - **Deterministic ranking**: results order by score, then recency, then id.
19//! Identical data returns identical output.
20//! - **Namespaced collections**: records are scoped by `namespace / index /
21//! partition`, so one store serves many collections.
22//! - **Memory or disk**: run fully in memory, or give FeOxDB a file path for
23//! persistence with write-behind buffering and explicit commit-point flushes.
24//!
25//! ## Quick start
26//!
27//! ```
28//! use feox_vector::{Store, StoreConfig, VectorStore, VectorQueryInput, VectorUpsertInput, VectorUpsertRecord};
29//!
30//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
31//! let store = Store::open(StoreConfig::default())?;
32//! let vectors = VectorStore::new(store);
33//!
34//! vectors.upsert("app", "docs", "main", VectorUpsertInput {
35//! records: vec![VectorUpsertRecord {
36//! id: "doc-1".to_string(),
37//! values: vec![0.9, 0.1, 0.0],
38//! metadata: Default::default(),
39//! }],
40//! })?;
41//!
42//! let result = vectors.query("app", "docs", "main", VectorQueryInput {
43//! vector: vec![1.0, 0.0, 0.0],
44//! top_k: Some(5),
45//! filter: Default::default(),
46//! min_score: None,
47//! mode: None,
48//! ef_search: None,
49//! candidate_limit: None,
50//! })?;
51//! assert_eq!(result.matches[0].id, "doc-1");
52//! # Ok(())
53//! # }
54//! ```
55//!
56//! ## ANN mode
57//!
58//! Pass `mode: Some(VectorQueryMode::Ann)` to use the HNSW index. The first ANN
59//! query on a scope schedules a background build and serves the query exactly in
60//! the meantime. Dirty or rebuilding scopes also serve exact results, preserving
61//! read-after-write semantics. Rebuilds are triggered automatically after writes,
62//! or explicitly via
63//! [`VectorStore::rebuild_ann`] / [`VectorStore::rebuild_ann_with_config`].
64
65mod ann;
66mod codec;
67mod filter;
68mod keys;
69mod model;
70mod storage;
71mod store;
72mod validation;
73
74pub use feox_ann::AnnConfig;
75pub use model::{
76 VectorDeleteInput, VectorDeleteResult, VectorError, VectorMatch, VectorQueryInput,
77 VectorQueryMode, VectorQueryResult, VectorRecord, VectorUpsertInput, VectorUpsertRecord,
78 VectorUpsertResult,
79};
80pub use storage::{KeyValue, Store, StoreConfig, StoreError, StoreStats};
81pub use store::VectorStore;
82
83pub type Result<T> = std::result::Result<T, VectorError>;
84
85#[cfg(test)]
86mod tests;