example/
example.rs

1use casper_client::{
2    CasperClient,
3    CreateCollectionRequest,
4    InsertRequest,
5    SearchRequest,
6    BatchUpdateRequest,
7    BatchInsertOperation,
8    CreateHNSWIndexRequest,
9    HNSWIndexConfig,
10    CreatePqRequest,
11};
12
13#[tokio::main]
14async fn main() -> Result<(), Box<dyn std::error::Error>> {
15    // Resolve host and ports from environment (with sane defaults)
16    let host = std::env::var("CASPER_HOST")
17        .unwrap_or_else(|_| "http://127.0.0.1".to_string());
18    let http_port: u16 = std::env::var("CASPER_HTTP_PORT")
19        .ok()
20        .and_then(|v| v.parse().ok())
21        .unwrap_or(8080);
22    let grpc_port: u16 = std::env::var("CASPER_GRPC_PORT")
23        .ok()
24        .and_then(|v| v.parse().ok())
25        .unwrap_or(50051);
26
27    // Create a client for HTTP & gRPC APIs
28    let client = CasperClient::new(&host, http_port, grpc_port)?;
29    
30    println!("Casper Vector Database Client Example");
31
32    // 1. Create a collection
33    println!("\nCreating collection...");
34    let create_request = CreateCollectionRequest {
35        dim: 128,
36        max_size: 10000,
37    };
38    client.create_collection("example_collection", create_request).await?;
39    println!("Collection 'example_collection' created successfully");
40
41    // 2. Insert some vectors
42    println!("\nInserting vectors...");
43    for i in 1..=5 {
44        let vector = generate_random_vector(128, i as f32);
45        let insert_request = InsertRequest {
46            id: i,
47            vector,
48        };
49        client.insert_vector("example_collection", insert_request).await?;
50        println!("Vector {} inserted", i);
51    }
52
53    // 3. Batch insert more vectors
54    println!("\nBatch inserting vectors...");
55    let mut inserts = Vec::new();
56    for i in 6..=10 {
57        let vector = generate_random_vector(128, i as f32);
58        inserts.push(BatchInsertOperation { id: i, vector });
59    }
60    let batch_request = BatchUpdateRequest { insert: inserts, delete: vec![] };
61    client.batch_update("example_collection", batch_request).await?;
62    println!("Batch insert completed");
63
64    // 4. Create HNSW index
65    println!("\nCreating HNSW index...");
66    let hnsw_request = CreateHNSWIndexRequest {
67        hnsw: HNSWIndexConfig {
68            metric: "inner-product".to_string(),
69            quantization: "f32".to_string(),
70            m: 16,
71            m0: 32,
72            ef_construction: 200,
73            pq_name: None,
74        },
75        normalization: Some(true),
76    };
77    client.create_hnsw_index("example_collection", hnsw_request).await?;
78    println!("HNSW index created");
79
80    // 5. Search for similar vectors
81    println!("\nSearching for similar vectors...");
82    let query_vector = generate_random_vector(128, 1.0);
83    let search_request = SearchRequest {
84        vector: query_vector,
85        limit: Some(5),
86    };
87    let results = client.search("example_collection", 30, search_request).await?;
88
89    println!("Found {} similar vectors:", results.len());
90    for (i, result) in results.iter().enumerate() {
91        println!("  {}. ID: {}, Score: {:.4}", i + 1, result.id, result.score);
92    }
93
94    // 6. Get a specific vector
95    println!("\nGetting vector by ID...");
96    if let Some(vector) = client.get_vector("example_collection", 1).await? {
97        println!("Vector 1 retrieved: {} dimensions", vector.len());
98    } else {
99        println!("Vector 1 not found");
100    }
101
102    // 7. Delete a vector
103    println!("\nDeleting vector...");
104    client.delete_vector("example_collection", casper_client::DeleteRequest { id: 10 }).await?;
105    println!("Vector 10 deleted");
106
107    // 8. Get collection information
108    println!("\nGetting collection information...");
109    let collection_info = client.get_collection("example_collection").await?;
110    println!("Collection info retrieved:");
111    println!("  - Name: {}", collection_info.name);
112    println!("  - Dimension: {}", collection_info.dimension);
113    println!("  - Mutable: {}", collection_info.mutable);
114    println!("  - Has index: {}", collection_info.has_index);
115    println!("  - Max size: {}", collection_info.max_size);
116    if let Some(index) = collection_info.index {
117        if let Some(hnsw) = index.hnsw {
118            println!("  - Index: HNSW");
119            println!("    - Metric: {}", hnsw.metric);
120            println!("    - Quantization: {}", hnsw.quantization);
121            println!("    - M: {}", hnsw.m);
122            println!("    - M0: {}", hnsw.m0);
123            println!("    - Ef construction: {}", hnsw.ef_construction);
124            println!("    - Normalization: {}", index.normalization);
125        } else {
126            println!("  - Index present (non-HNSW)");
127        }
128    }
129
130    // 9. List collections
131    println!("\nListing collections...");
132    let collections = client.list_collections().await?;
133    println!("Found {} collections:", collections.collections.len());
134    for collection in collections.collections {
135        println!("  - {} (dim: {}, size: {}, mutable: {}, has_index: {})",
136                 collection.name,
137                 collection.dimension,
138                 collection.size,
139                 collection.mutable,
140                 collection.has_index);
141    }
142
143    // 10. Delete the index
144    println!("\nDeleting index...");
145    client.delete_index("example_collection").await?;
146    println!("Index deleted successfully");
147
148    // 11. Delete the collection
149    println!("\nDeleting collection...");
150    client.delete_collection("example_collection").await?;
151    println!("Collection 'example_collection' deleted successfully");
152
153    // A. Matrix operations (gRPC upload + HTTP management)
154    println!("\nCreating matrices via gRPC...");
155
156    let dim = 3usize;
157    let m1_name = "example_matrix_1";
158    let m2_name = "example_matrix_2";
159
160    // Two simple 3D vectors for each matrix
161    let m1_vectors: Vec<f32> = vec![
162        1.0, 2.0, 3.0,
163        4.0, 5.0, 6.0,
164    ];
165    let m2_vectors: Vec<f32> = vec![
166        0.1, 0.2, 0.3,
167        0.4, 0.5, 0.6,
168    ];
169
170    let res1 = client
171        .upload_matrix(m1_name, dim, m1_vectors.clone(), 6)
172        .await?;
173    println!("Uploaded matrix '{}' via gRPC: {}", m1_name, res1.message);
174
175    let res2 = client
176        .upload_matrix(m2_name, dim, m2_vectors.clone(), 6)
177        .await?;
178    println!("Uploaded matrix '{}' via gRPC: {}", m2_name, res2.message);
179
180    println!("\nListing matrices...");
181    let matrices = client.list_matrices().await?;
182    println!("Found {} matrices:", matrices.len());
183    for m in &matrices {
184        println!(
185            "  - {} (dim: {}, len: {}, enabled: {})",
186            m.name, m.dim, m.len, m.enabled
187        );
188    }
189
190    println!("\nGetting matrix info individually...");
191    let info1 = client.get_matrix_info(m1_name).await?;
192    println!(
193        "  - {}: dim={}, len={}, enabled={}",
194        info1.name, info1.dim, info1.len, info1.enabled
195    );
196    let info2 = client.get_matrix_info(m2_name).await?;
197    println!(
198        "  - {}: dim={}, len={}, enabled={}",
199        info2.name, info2.dim, info2.len, info2.enabled
200    );
201
202    // B. PQ operations (HTTP)
203    println!("\nCreating PQ...");
204    let pq_name = "example_pq";
205    // Use the two matrices we just created as PQ codebooks.
206    // Each has dim=3, so total PQ dim is 6.
207    let pq_request = CreatePqRequest {
208        dim: dim * 2, // sum of codebooks dims (3 + 3)
209        codebooks: vec![m1_name.to_string(), m2_name.to_string()],
210    };
211
212    match client.create_pq(pq_name, pq_request).await {
213        Ok(()) => println!("PQ '{}' created", pq_name),
214        Err(e) => {
215            println!("Failed to create PQ '{}': {}", pq_name, e);
216        }
217    }
218
219    println!("\nListing PQs...");
220    let pqs = client.list_pqs().await?;
221    println!("Found {} PQs:", pqs.len());
222    for pq in &pqs {
223        println!(
224            "  - {} (dim: {}, codebooks: {:?}, enabled: {})",
225            pq.name, pq.dim, pq.codebooks, pq.enabled
226        );
227    }
228
229    println!("\nGetting PQ info individually...");
230    match client.get_pq(pq_name).await {
231        Ok(pq_info) => {
232            println!(
233                "  - {}: dim={}, codebooks={:?}, enabled={}",
234                pq_info.name, pq_info.dim, pq_info.codebooks, pq_info.enabled
235            );
236        }
237        Err(e) => {
238            println!("Failed to get PQ '{}': {}", pq_name, e);
239        }
240    }
241
242    println!("\nDeleting PQ '{}'...", pq_name);
243    match client.delete_pq(pq_name).await {
244        Ok(()) => println!("PQ '{}' deleted", pq_name),
245        Err(e) => println!("Failed to delete PQ '{}': {}", pq_name, e),
246    }
247
248    // C. Delete matrices after PQ is gone
249    println!("\nDeleting matrices '{}' and '{}'...", m1_name, m2_name);
250    client.delete_matrix(m1_name).await?;
251    client.delete_matrix(m2_name).await?;
252    println!("Matrices '{}' and '{}' deleted", m1_name, m2_name);
253
254    let matrices_after = client.list_matrices().await?;
255    println!("Matrices after deletion ({} total):", matrices_after.len());
256    for m in &matrices_after {
257        println!(
258            "  - {} (dim: {}, len: {}, enabled: {})",
259            m.name, m.dim, m.len, m.enabled
260        );
261    }
262    
263    println!("\nExample completed successfully!");
264    Ok(())
265}
266
267/// Generate a random vector for demonstration
268fn generate_random_vector(dim: usize, seed: f32) -> Vec<f32> {
269    use std::collections::hash_map::DefaultHasher;
270    use std::hash::{Hash, Hasher};
271    
272    let mut vector = Vec::with_capacity(dim);
273    for i in 0..dim {
274        let mut hasher = DefaultHasher::new();
275        (seed * 1000.0 + i as f32).to_bits().hash(&mut hasher);
276        let hash = hasher.finish();
277        let value = (hash as f32 / u64::MAX as f32) * 2.0 - 1.0; // Normalize to [-1, 1]
278        vector.push(value);
279    }
280    
281    // Normalize the vector
282    let norm: f32 = vector.iter().map(|x| x * x).sum::<f32>().sqrt();
283    if norm > 0.0 {
284        for value in &mut vector {
285            *value /= norm;
286        }
287    }
288    
289    vector
290}