manifold-graph
Graph storage optimizations for the Manifold embedded database.
Overview
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.
Features
- Automatic bidirectional indexes - Efficient queries for both outgoing and incoming edges
- UUID-based vertices - Fixed-width 16-byte vertex IDs with proper ordering
- Type-safe edge properties - Fixed-width
(bool, f32)tuple foris_activeandweight - Atomic updates - Both forward and reverse indexes updated in same transaction
- Efficient traversal - Range scans leverage tuple key ordering for O(k) queries
- Batch operations - High-throughput bulk loading with
add_edges_batch() - Integration ready -
EdgeSourcetrait for external graph algorithm libraries
Quick Start
use ColumnFamilyDatabase;
use ;
use Uuid;
// Open database and column family
let db = open?;
let cf = db.column_family_or_create?;
let user1 = new_v4;
let user2 = new_v4;
// Write edges
// Read with efficient traversal
let read_txn = cf.begin_read?;
let graph = open?;
// Query outgoing edges
for edge_result in graph.outgoing_edges?
// Query incoming edges
for edge_result in graph.incoming_edges?
Batch Operations
For high-throughput graph loading, use batch operations which leverage Manifold's WAL group commit:
let edges = vec!;
let write_txn = cf.begin_write?;
let mut graph = open?;
// Insert all edges in one batch
let count = graph.add_edges_batch?;
println!;
drop;
write_txn.commit?;
Edge Properties
Edges store two fixed-width properties:
is_active: bool- For active/passive edges, soft deletes, hidden edgesweight: f32- General-purpose edge weight or score
These are stored as a fixed-width tuple (bool, f32) for zero-overhead serialization (5 bytes total).
Architecture
Bidirectional Storage
Each GraphTable maintains two internal tables:
- Forward table:
(source, edge_type, target) -> (is_active, weight) - Reverse table:
(target, edge_type, source) -> (is_active, weight)
Both tables are updated atomically, enabling efficient queries in both directions.
Performance Characteristics
- Write: O(log n) × 2 for forward + reverse B-tree inserts, benefits from WAL group commit
- Read outgoing: O(log n) lookup + O(k) scan where k = outgoing edge count
- Read incoming: O(log n) lookup + O(k) scan where k = incoming edge count
- Key size: ~37-40 bytes (32 bytes UUIDs + 5-8 bytes edge type)
- Value size: 5 bytes fixed-width (1 byte bool + 4 bytes f32)
Integration with Graph Libraries
The EdgeSource trait enables integration with external graph algorithm libraries:
use EdgeSource;
use DiGraph;
let read_txn = cf.begin_read?;
let graph = open?;
// Build petgraph DiGraph
let mut pg_graph: = new;
let mut node_map = new;
// Add nodes...
for page in &pages
// Add edges using EdgeSource
for edge_result in graph.iter_edges?
// Run petgraph algorithms
let pagerank = /* compute PageRank */;
let sccs = kosaraju_scc;
Examples
The crate includes comprehensive examples demonstrating real-world usage:
1. Social Network (examples/social_network.rs)
Twitter-like social network with:
- Multiple edge types (follows, blocks, mutes)
- Bidirectional queries (followers/following)
- Edge property updates
- Mutual connection detection
2. Petgraph Integration (examples/petgraph_integration.rs)
Integration with petgraph for:
- PageRank algorithm
- Strongly connected components
- Shortest paths (Dijkstra)
- Centrality measures
3. Knowledge Graph (examples/knowledge_graph.rs)
Movie/entertainment knowledge graph with:
- Multiple entity types (Person, Film, Studio, Genre)
- Rich relationship types (directed, acted_in, produced_by, genre_of)
- Multi-hop queries
- Recommendation engine
4. Dependency Graph (examples/dependency_graph.rs)
Package management graph with:
- Cycle detection (DFS)
- Topological sorting (Kahn's algorithm)
- Impact analysis (what breaks if X is removed)
- Dependency depth analysis
Use Cases
- Social networks - Followers, friends, blocks, mutes
- Knowledge graphs - Entity relationships, semantic networks
- Dependency tracking - Package management, build systems
- Recommendation systems - Product relationships, collaborative filtering
- Network analysis - Web graphs, citation networks
- Access control - Permission graphs, role hierarchies
Combining with Other Domain Layers
manifold-graph works seamlessly with other manifold domain layers in the same database:
use ColumnFamilyDatabase;
use GraphTable;
use VectorTable;
let db = open?;
// Use graphs and vectors in the same database
let graph_cf = db.column_family_or_create?;
let vectors_cf = db.column_family_or_create?;
// Store social graph
let txn = graph_cf.begin_write?;
let mut graph = open?;
graph.add_edge?;
// Store user embeddings
let txn = vectors_cf.begin_write?;
let mut vectors = open?;
vectors.insert?;
Requirements
- Rust 1.70+ (for const generics)
manifoldwithuuidfeature enabled
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Contributing
Contributions are welcome! This crate follows the patterns established in manifold-vectors.
Related Crates
- manifold - Core embedded database
- manifold-vectors - Vector storage for embeddings
- petgraph - Graph algorithms library