Regional Sales Analytics with Uni (Rust)¶
Combining Graph Traversal with Columnar Aggregation using Uni's native Rust API.
In [ ]:
Copied!
:dep uni-db = { path = "../../../crates/uni" }
:dep tokio = { version = "1", features = ["full"] }
:dep serde_json = "1"
:dep uni-db = { path = "../../../crates/uni" }
:dep tokio = { version = "1", features = ["full"] }
:dep serde_json = "1"
In [ ]:
Copied!
use uni::{Uni, DataType, IndexType, ScalarType, VectorMetric, VectorAlgo, VectorIndexCfg};
use std::collections::HashMap;
use serde_json::json;
// Helper macro to run async code in evcxr
macro_rules! run {
($e:expr) => {
tokio::runtime::Runtime::new().unwrap().block_on($e)
};
}
use uni::{Uni, DataType, IndexType, ScalarType, VectorMetric, VectorAlgo, VectorIndexCfg};
use std::collections::HashMap;
use serde_json::json;
// Helper macro to run async code in evcxr
macro_rules! run {
($e:expr) => {
tokio::runtime::Runtime::new().unwrap().block_on($e)
};
}
In [ ]:
Copied!
let db_path = "./sales_db";
// Clean up any existing database
if std::path::Path::new(db_path).exists() {
std::fs::remove_dir_all(db_path).unwrap();
}
let db = run!(Uni::open(db_path).build()).unwrap();
println!("Opened database at {}", db_path);
let db_path = "./sales_db";
// Clean up any existing database
if std::path::Path::new(db_path).exists() {
std::fs::remove_dir_all(db_path).unwrap();
}
let db = run!(Uni::open(db_path).build()).unwrap();
println!("Opened database at {}", db_path);
1. Schema¶
In [ ]:
Copied!
run!(async {
db.schema()
.label("Region")
.property("name", DataType::String)
.label("Order")
.property("amount", DataType::Float64)
.edge_type("SHIPPED_TO", &["Order"], &["Region"])
.apply()
.await
}).unwrap();
println!("Sales analytics schema created");
run!(async {
db.schema()
.label("Region")
.property("name", DataType::String)
.label("Order")
.property("amount", DataType::Float64)
.edge_type("SHIPPED_TO", &["Order"], &["Region"])
.apply()
.await
}).unwrap();
println!("Sales analytics schema created");
2. Ingest Data¶
One region, 100 orders.
In [ ]:
Copied!
// Create region
let regions = vec![
HashMap::from([("name".to_string(), json!("North"))]),
];
let region_vids = run!(db.bulk_insert_vertices("Region", regions)).unwrap();
let north = region_vids[0];
// Create 100 orders with varying amounts
let orders: Vec<HashMap<String, serde_json::Value>> = (0..100)
.map(|i| HashMap::from([
("amount".to_string(), json!(10.0 * (i + 1) as f64))
]))
.collect();
let order_vids = run!(db.bulk_insert_vertices("Order", orders)).unwrap();
// Ship all orders to North region
let edges: Vec<_> = order_vids.iter()
.map(|vid| (*vid, north, HashMap::new()))
.collect();
run!(db.bulk_insert_edges("SHIPPED_TO", edges)).unwrap();
run!(db.flush()).unwrap();
println!("Inserted {} orders shipped to North region", order_vids.len());
// Create region
let regions = vec![
HashMap::from([("name".to_string(), json!("North"))]),
];
let region_vids = run!(db.bulk_insert_vertices("Region", regions)).unwrap();
let north = region_vids[0];
// Create 100 orders with varying amounts
let orders: Vec> = (0..100)
.map(|i| HashMap::from([
("amount".to_string(), json!(10.0 * (i + 1) as f64))
]))
.collect();
let order_vids = run!(db.bulk_insert_vertices("Order", orders)).unwrap();
// Ship all orders to North region
let edges: Vec<_> = order_vids.iter()
.map(|vid| (*vid, north, HashMap::new()))
.collect();
run!(db.bulk_insert_edges("SHIPPED_TO", edges)).unwrap();
run!(db.flush()).unwrap();
println!("Inserted {} orders shipped to North region", order_vids.len());
3. Analytical Query¶
Sum of amounts for orders in a region.
In [ ]:
Copied!
let query = r#"
MATCH (r:Region {name: 'North'})<-[:SHIPPED_TO]-(o:Order)
RETURN SUM(o.amount) as total
"#;
let results = run!(db.query(query)).unwrap();
println!("Total Sales for North Region: {:?}", results.rows[0]);
// Expected: 10 * (1 + 2 + ... + 100) = 10 * 5050 = 50500
let query = r#"
MATCH (r:Region {name: 'North'})<-[:SHIPPED_TO]-(o:Order)
RETURN SUM(o.amount) as total
"#;
let results = run!(db.query(query)).unwrap();
println!("Total Sales for North Region: {:?}", results.rows[0]);
// Expected: 10 * (1 + 2 + ... + 100) = 10 * 5050 = 50500