| Crates.io | manifold-graph |
| lib.rs | manifold-graph |
| version | 0.1.0 |
| created_at | 2025-11-03 03:30:16.360971+00 |
| updated_at | 2025-11-03 03:30:16.360971+00 |
| description | Graph storage optimizations for Manifold embedded database |
| homepage | https://github.com/tomWhiting/manifold |
| repository | https://github.com/tomWhiting/manifold |
| max_upload_size | |
| id | 1913845 |
| size | 635,455 |
Graph storage optimizations for the Manifold embedded database.
manifold-graph provides ergonomic, type-safe wrappers around Manifold's core primitives for storing and querying graph edges with automatic bidirectional indexes. It does not implement graph algorithms - instead, it focuses on efficient persistent storage and provides integration traits for external graph libraries like petgraph.
(bool, f32) tuple for is_active and weightadd_edges_batch()EdgeSource trait for external graph algorithm librariesuse manifold::column_family::ColumnFamilyDatabase;
use manifold_graph::{GraphTable, GraphTableRead};
use uuid::Uuid;
// Open database and column family
let db = ColumnFamilyDatabase::open("my.db")?;
let cf = db.column_family_or_create("social")?;
let user1 = Uuid::new_v4();
let user2 = Uuid::new_v4();
// Write edges
{
let write_txn = cf.begin_write()?;
let mut graph = GraphTable::open(&write_txn, "follows")?;
graph.add_edge(&user1, "follows", &user2, true, 1.0)?;
drop(graph);
write_txn.commit()?;
}
// Read with efficient traversal
let read_txn = cf.begin_read()?;
let graph = GraphTableRead::open(&read_txn, "follows")?;
// Query outgoing edges
for edge_result in graph.outgoing_edges(&user1)? {
let edge = edge_result?;
println!("{:?} -[{}]-> {:?}", edge.source, edge.edge_type, edge.target);
}
// Query incoming edges
for edge_result in graph.incoming_edges(&user2)? {
let edge = edge_result?;
println!("{:?} <-[{}]- {:?}", edge.target, edge.edge_type, edge.source);
}
For high-throughput graph loading, use batch operations which leverage Manifold's WAL group commit:
let edges = vec![
(user1, "follows", user2, true, 1.0),
(user1, "follows", user3, true, 0.8),
(user2, "follows", user3, true, 0.9),
];
let write_txn = cf.begin_write()?;
let mut graph = GraphTable::open(&write_txn, "follows")?;
// Insert all edges in one batch
let count = graph.add_edges_batch(edges, false)?;
println!("Inserted {} edges", count);
drop(graph);
write_txn.commit()?;
Edges store two fixed-width properties:
is_active: bool - For active/passive edges, soft deletes, hidden edgesweight: f32 - General-purpose edge weight or scoreThese are stored as a fixed-width tuple (bool, f32) for zero-overhead serialization (5 bytes total).
Each GraphTable maintains two internal tables:
(source, edge_type, target) -> (is_active, weight)(target, edge_type, source) -> (is_active, weight)Both tables are updated atomically, enabling efficient queries in both directions.
The EdgeSource trait enables integration with external graph algorithm libraries:
use manifold_graph::EdgeSource;
use petgraph::graph::DiGraph;
let read_txn = cf.begin_read()?;
let graph = GraphTableRead::open(&read_txn, "links")?;
// Build petgraph DiGraph
let mut pg_graph: DiGraph<Uuid, f32> = DiGraph::new();
let mut node_map = HashMap::new();
// Add nodes...
for page in &pages {
let idx = pg_graph.add_node(page.id);
node_map.insert(page.id, idx);
}
// Add edges using EdgeSource
for edge_result in graph.iter_edges()? {
let edge = edge_result?;
if edge.is_active {
pg_graph.add_edge(
node_map[&edge.source],
node_map[&edge.target],
edge.weight
);
}
}
// Run petgraph algorithms
let pagerank = /* compute PageRank */;
let sccs = kosaraju_scc(&pg_graph);
The crate includes comprehensive examples demonstrating real-world usage:
examples/social_network.rs)Twitter-like social network with:
cargo run --example social_network -p manifold-graph
examples/petgraph_integration.rs)Integration with petgraph for:
cargo run --example petgraph_integration -p manifold-graph
examples/knowledge_graph.rs)Movie/entertainment knowledge graph with:
cargo run --example knowledge_graph -p manifold-graph
examples/dependency_graph.rs)Package management graph with:
cargo run --example dependency_graph -p manifold-graph
manifold-graph works seamlessly with other manifold domain layers in the same database:
use manifold::column_family::ColumnFamilyDatabase;
use manifold_graph::GraphTable;
use manifold_vectors::VectorTable;
let db = ColumnFamilyDatabase::open("my_app.db")?;
// Use graphs and vectors in the same database
let graph_cf = db.column_family_or_create("social")?;
let vectors_cf = db.column_family_or_create("embeddings")?;
// Store social graph
let txn = graph_cf.begin_write()?;
let mut graph = GraphTable::open(&txn, "follows")?;
graph.add_edge(&user1, "follows", &user2, true, 1.0)?;
// Store user embeddings
let txn = vectors_cf.begin_write()?;
let mut vectors = VectorTable::<768>::open(&txn, "user_vectors")?;
vectors.insert("user1", &embedding)?;
manifold with uuid feature enabledLicensed under either of:
at your option.
Contributions are welcome! This crate follows the patterns established in manifold-vectors.