-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex_selection.rs
More file actions
64 lines (55 loc) · 2.19 KB
/
Copy pathindex_selection.rs
File metadata and controls
64 lines (55 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Copyright 2026 James Gober. Licensed under Apache-2.0 OR MIT.
//! Choosing an index through `IqdbConfig`: the exact flat default, an HNSW
//! graph, and an IVF clustering — plus a result cache and `optimize`.
//!
//! Run with `cargo run --example index_selection`.
use iqdb::{
CacheConfig, DistanceMetric, HnswConfig, IndexKind, Iqdb, IqdbConfig, IvfConfig, Result,
Vector, VectorId,
};
/// Build a small corpus into whichever database is passed.
fn load(db: &Iqdb) -> Result<()> {
for i in 0..50u64 {
let x = (i as f32) * 0.1;
db.upsert(VectorId::from(i), Vector::new(vec![x, 1.0 - x])?, None)?;
}
Ok(())
}
fn nearest(db: &Iqdb, label: &str) -> Result<()> {
let hits = db.search(&Vector::new(vec![0.0, 1.0])?, 3)?;
let ids: Vec<String> = hits.iter().map(|h| h.id.to_string()).collect();
println!("{label:<22} top-3 ids: {ids:?}");
Ok(())
}
fn main() -> Result<()> {
let metric = DistanceMetric::Euclidean;
// Tier 1: the exact flat index, zero configuration.
let flat = Iqdb::open_in_memory(2, metric)?;
load(&flat)?;
nearest(&flat, "flat (exact)")?;
// Tier 2: an HNSW graph, tuned for a wider search beam, with a cache.
let hnsw = Iqdb::open_in_memory_with(
IqdbConfig::new(2, metric)
.index(IndexKind::Hnsw(HnswConfig::default().with_ef_search(128)))
.cache(CacheConfig::new().capacity(1_024)),
)?;
load(&hnsw)?;
nearest(&hnsw, "hnsw (approximate)")?;
// The second identical query is served from the cache.
let _ = hnsw.search(&Vector::new(vec![0.0, 1.0])?, 3)?;
if let Some(stats) = hnsw.cache_stats() {
println!(" cache hits={} misses={}", stats.hits, stats.misses);
}
// Tier 2: an IVF clustering. It trains lazily on the first search; after
// many writes, `optimize` retrains the centroids over the current data.
let ivf = Iqdb::open_in_memory_with(IqdbConfig::new(2, metric).index(IndexKind::Ivf(
IvfConfig::default().with_n_clusters(8).with_n_probes(8),
)))?;
load(&ivf)?;
nearest(&ivf, "ivf (approximate)")?;
ivf.optimize()?;
nearest(&ivf, "ivf (after optimize)")?;
flat.close()?;
hnsw.close()?;
ivf.close()
}