1use recern_vector::{CollectionConfig, Database, Filter, Metric, RecallOptions, SearchOptions};
7use serde_json::json;
8
9fn main() -> recern_vector::Result<()> {
10 let path = std::env::temp_dir().join("recern-vector-quickstart.rvec");
11 let _ = std::fs::remove_file(&path);
12 let _ = std::fs::remove_file(format!("{}.wal", path.display()));
13
14 let mut db = Database::create(&path)?;
15 let docs = db.create_collection("docs", CollectionConfig::new(32, Metric::Cosine))?;
16
17 let records: Vec<_> = (0..10_000)
19 .map(|i| {
20 let vector: Vec<f32> = (0..32).map(|d| pseudo_random(i * 32 + d)).collect();
21 let lang = ["en", "de", "fr"][i % 3];
22 (
23 format!("doc-{i}"),
24 vector,
25 Some(json!({"lang": lang, "year": 2015 + i % 10})),
26 )
27 })
28 .collect();
29 let query = records[42].1.clone();
30 docs.upsert_many(records)?;
31 println!("{} records", docs.len());
32
33 let filter = Filter::from_json(&json!({"lang": "en", "year": {"$gte": 2020}}))?;
35 let _same = Filter::And(vec![
37 Filter::eq("lang", "en"),
38 Filter::between("year", Some(2020.0), None),
39 ]);
40 let report = docs.explain(&query, 3, &SearchOptions::default().filter(filter))?;
41 for hit in &report.hits {
42 println!(
43 " {:<10} distance={:.4} {}",
44 hit.id,
45 hit.distance,
46 hit.metadata.as_ref().unwrap()
47 );
48 }
49 println!(
50 "strategy={} visited={} selectivity={:.1}% time={:?}",
51 report.strategy,
52 report.visited,
53 report.filter_selectivity.unwrap_or(1.0) * 100.0,
54 report.elapsed
55 );
56
57 let stats = docs.stats();
59 println!(
60 "layers={:?} unreachable={}",
61 stats.nodes_per_layer, stats.unreachable
62 );
63 let recall = docs.estimate_recall(&RecallOptions {
64 ef_values: vec![16, 64],
65 ..Default::default()
66 })?;
67 for point in &recall.points {
68 println!(
69 " ef={:<3} recall@{}={:.3}",
70 point.ef, recall.k, point.recall
71 );
72 }
73
74 db.save()?;
75 let reopened = Database::open(&path)?;
76 println!("reopened: {} records", reopened.collection("docs")?.len());
77 Ok(())
78}
79
80fn pseudo_random(seed: usize) -> f32 {
82 let mut x = seed as u64 ^ 0x9E37_79B9_7F4A_7C15;
83 x = (x ^ (x >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
84 x = (x ^ (x >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
85 ((x ^ (x >> 31)) as f64 / u64::MAX as f64 * 2.0 - 1.0) as f32
86}