graph_api_benches/index/vertex_label/
mod.rs

1use criterion::{BenchmarkGroup, measurement::WallTime};
2use graph_api_derive::{EdgeExt, VertexExt};
3use graph_api_lib::Graph;
4#[cfg(feature = "element-removal")]
5use graph_api_lib::SupportsElementRemoval;
6use std::collections::HashSet;
7use std::fmt::Debug;
8use uuid::Uuid;
9
10// Define a model with ONLY label index (no property indexes)
11#[derive(Debug, Clone, VertexExt)]
12pub enum Vertex {
13    // No hash, range, or fulltext indices - only label (enum variant) is indexed
14    Person {
15        name: String,
16        age: u64,
17        unique_id: Uuid,
18        username: String,
19        biography: String,
20    },
21    Project {
22        name: String,
23    },
24    Rust,
25}
26
27#[derive(Debug, Clone, EdgeExt)]
28pub enum Edge {
29    Knows { since: i32 },
30    Created,
31    Language { name: String },
32}
33
34// Generate test data with the LabelVertex and LabelEdge models
35pub fn populate_test_data<G>(graph: &mut G) -> (HashSet<G::VertexId>, G::VertexId, G::VertexId)
36where
37    G: Graph<Vertex = Vertex, Edge = Edge>,
38{
39    let mut person_ids = HashSet::new();
40
41    // Create person vertices for label queries
42    for i in 0..100 {
43        let id = graph.add_vertex(Vertex::Person {
44            name: format!("Person{}", i),
45            age: 25 + (i % 50) as u64,
46            unique_id: Uuid::new_v4(),
47            username: format!("user{}", i),
48            biography: format!("Bio for person {}", i),
49        });
50        person_ids.insert(id);
51    }
52
53    // Add some non-person vertices
54    let project = graph.add_vertex(Vertex::Project {
55        name: "TestProject".to_string(),
56    });
57
58    let rust = graph.add_vertex(Vertex::Rust);
59
60    (person_ids, project, rust)
61}
62
63// Individual benchmark functions
64
65#[cfg(feature = "vertex-label-index")]
66pub fn bench_label_lookup<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
67where
68    G: Graph<Vertex = Vertex, Edge = Edge> + graph_api_lib::SupportsVertexLabelIndex,
69{
70    // Benchmark vertex label index lookup
71    group.throughput(criterion::Throughput::Elements(1));
72    group.bench_function("vertex_label_lookup", |b| {
73        // Setup: Create graph with test data
74        let mut graph = setup();
75        populate_test_data(&mut graph);
76
77        b.iter(|| {
78            // Query by label (Person)
79            let results = graph
80                .walk()
81                .vertices(Vertex::person())
82                .take(10)
83                .collect::<Vec<_>>();
84
85            assert!(!results.is_empty());
86            results
87        })
88    });
89}
90
91#[cfg(not(feature = "vertex-label-index"))]
92pub fn bench_label_lookup<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
93where
94    G: Graph<Vertex = Vertex, Edge = Edge>,
95{
96    // No-op when feature is disabled
97}
98
99#[cfg(feature = "vertex-label-index")]
100pub fn bench_label_insertion<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
101where
102    G: Graph<Vertex = Vertex, Edge = Edge> + graph_api_lib::SupportsVertexLabelIndex,
103{
104    // Benchmark insertion with label index
105    group.bench_function("vertex_label_insertion", |b| {
106        let mut graph = setup();
107        let mut counter = 0;
108
109        b.iter(|| {
110            counter += 1;
111
112            graph.add_vertex(Vertex::Person {
113                name: format!("Test{}", counter),
114                age: 30,
115                unique_id: Uuid::new_v4(),
116                username: format!("test_user{}", counter),
117                biography: "Test biography".to_string(),
118            })
119        })
120    });
121}
122
123#[cfg(not(feature = "vertex-label-index"))]
124pub fn bench_label_insertion<G>(
125    _group: &mut BenchmarkGroup<WallTime>,
126    _setup: impl Fn() -> G + Clone,
127) where
128    G: Graph<Vertex = Vertex, Edge = Edge>,
129{
130    // No-op when feature is disabled
131}
132
133#[cfg(all(feature = "vertex-label-index", feature = "element-removal"))]
134pub fn bench_label_removal<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
135where
136    G: Graph<Vertex = Vertex, Edge = Edge>
137        + graph_api_lib::SupportsVertexLabelIndex
138        + SupportsElementRemoval,
139{
140    // Benchmark removal with label index
141    group.bench_function("vertex_label_removal", |b| {
142        // Setup: Create a new graph for each iteration
143        b.iter_with_setup(
144            || {
145                let mut graph = setup();
146                let vertex_id = graph.add_vertex(Vertex::Person {
147                    name: "RemoveMe".to_string(),
148                    age: 25,
149                    unique_id: Uuid::new_v4(),
150                    username: "remove_user".to_string(),
151                    biography: "To be removed".to_string(),
152                });
153                (graph, vertex_id)
154            },
155            |(mut graph, vertex_id)| {
156                graph.remove_vertex(vertex_id);
157            },
158        )
159    });
160}
161
162#[cfg(not(all(feature = "vertex-label-index", feature = "element-removal")))]
163pub fn bench_label_removal<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
164where
165    G: Graph<Vertex = Vertex, Edge = Edge>,
166{
167    // No-op when features are disabled
168}