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 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.
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. Subsequent queries hit the snapshot. Rebuilds are triggered
61//! automatically when writes dirty the scope, or explicitly via
62//! [`VectorStore::rebuild_ann`] / [`VectorStore::rebuild_ann_with_config`].
63
64mod ann;
65mod codec;
66mod filter;
67mod keys;
68mod model;
69mod storage;
70mod store;
71mod validation;
72
73pub use feox_ann::AnnConfig;
74pub use model::{
75 VectorDeleteInput, VectorDeleteResult, VectorError, VectorMatch, VectorQueryInput,
76 VectorQueryMode, VectorQueryResult, VectorRecord, VectorUpsertInput, VectorUpsertRecord,
77 VectorUpsertResult,
78};
79pub use storage::{KeyValue, Store, StoreConfig, StoreError, StoreStats};
80pub use store::VectorStore;
81
82pub type Result<T> = std::result::Result<T, VectorError>;
83
84#[cfg(test)]
85mod tests;