graph_api_benches/index/vertex_full_text/
mod.rs

1use criterion::{BenchmarkGroup, measurement::WallTime};
2
3use graph_api_derive::{EdgeExt, VertexExt};
4use graph_api_lib::Graph;
5#[cfg(feature = "element-removal")]
6use graph_api_lib::SupportsElementRemoval;
7use std::fmt::Debug;
8use uuid::Uuid;
9
10// Define a model with ONLY full-text indexes (no hash or range indexes)
11#[derive(Debug, Clone, VertexExt)]
12pub enum Vertex {
13    Person {
14        name: String,
15        age: u64,
16        unique_id: Uuid,
17        username: String,
18        #[index(full_text)]
19        biography: String,
20    },
21    Project {
22        name: String,
23        #[index(full_text)]
24        description: String,
25    },
26    Rust,
27}
28
29#[derive(Debug, Clone, EdgeExt)]
30pub enum Edge {
31    Knows { since: i32 },
32    Created,
33    Language { name: String },
34}
35
36// Generate test data with the FullTextVertex and FullTextEdge models
37pub fn populate_test_data<G>(graph: &mut G)
38where
39    G: Graph<Vertex = Vertex, Edge = Edge>,
40{
41    // Create specific text content we'll search for
42    graph.add_vertex(Vertex::Person {
43        name: "Bryn".to_string(),
44        age: 45,
45        unique_id: Uuid::new_v4(),
46        username: "bryn".to_string(),
47        biography: "Experienced in graph database technologies and implementations".to_string(),
48    });
49
50    // Add some other vertices with various biography texts
51    let texts = [
52        "Loves working with data structures",
53        "Expert in graph algorithms and data models",
54        "Interested in database performance optimization",
55        "Has experience with various graph query languages",
56        "Works on graph visualization techniques",
57    ];
58
59    for i in 0..100 {
60        let text_idx = i % texts.len();
61        graph.add_vertex(Vertex::Person {
62            name: format!("Person{}", i),
63            age: 25 + (i % 50) as u64,
64            unique_id: Uuid::new_v4(),
65            username: format!("user{}", i),
66            biography: format!("{} and other skills", texts[text_idx]),
67        });
68    }
69
70    // Add project vertices with descriptions
71    graph.add_vertex(Vertex::Project {
72        name: "GraphAPI".to_string(),
73        description: "A Rust graph database API with support for various index types".to_string(),
74    });
75
76    graph.add_vertex(Vertex::Project {
77        name: "OtherProject".to_string(),
78        description: "Another project with different focus".to_string(),
79    });
80
81    graph.add_vertex(Vertex::Rust);
82}
83
84// Individual benchmark functions
85
86#[cfg(feature = "vertex-full-text-index")]
87pub fn bench_lookup<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
88where
89    G: Graph<Vertex = Vertex, Edge = Edge> + graph_api_lib::SupportsVertexFullTextIndex,
90{
91    // Benchmark full-text index lookup for biography
92    group.throughput(criterion::Throughput::Elements(1));
93    group.bench_function("vertex_fulltext_biography_lookup", |b| {
94        // Setup: Create graph with test data
95        let mut graph = setup();
96        populate_test_data(&mut graph);
97
98        b.iter(|| {
99            // Query by biography text containing "graph"
100            // Should find matches
101            graph
102                .walk()
103                .vertices(Vertex::person_by_biography("graph"))
104                .collect::<Vec<_>>()
105        })
106    });
107}
108
109#[cfg(not(feature = "vertex-full-text-index"))]
110pub fn bench_lookup<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
111where
112    G: Graph<Vertex = Vertex, Edge = Edge>,
113{
114    // No-op when feature is disabled
115}
116
117#[cfg(feature = "vertex-full-text-index")]
118pub fn bench_insertion<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
119where
120    G: Graph<Vertex = Vertex, Edge = Edge> + graph_api_lib::SupportsVertexFullTextIndex,
121{
122    // Benchmark insertion with full-text index
123    group.bench_function("vertex_fulltext_insertion", |b| {
124        let mut graph = setup();
125        let mut counter = 0;
126
127        b.iter(|| {
128            counter += 1;
129
130            graph.add_vertex(Vertex::Person {
131                name: format!("FullText{}", counter),
132                age: 30,
133                unique_id: Uuid::new_v4(),
134                username: format!("fulltext_user{}", counter),
135                biography: format!("This is a test biography for fulltext indexing {}", counter),
136            })
137        })
138    });
139}
140
141#[cfg(not(feature = "vertex-full-text-index"))]
142pub fn bench_insertion<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
143where
144    G: Graph<Vertex = Vertex, Edge = Edge>,
145{
146    // No-op when feature is disabled
147}
148
149#[cfg(all(feature = "vertex-full-text-index", feature = "element-removal"))]
150pub fn bench_removal<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
151where
152    G: Graph<Vertex = Vertex, Edge = Edge>
153        + graph_api_lib::SupportsVertexFullTextIndex
154        + SupportsElementRemoval,
155{
156    // Benchmark removal with full-text index
157    group.bench_function("vertex_fulltext_removal", |b| {
158        // Setup: Create a new graph for each iteration
159        b.iter_with_setup(
160            || {
161                let mut graph = setup();
162                let vertex_id = graph.add_vertex(Vertex::Person {
163                    name: "FullTextRemoveMe".to_string(),
164                    age: 25,
165                    unique_id: Uuid::new_v4(),
166                    username: "fulltext_remove_user".to_string(),
167                    biography: "To be removed from fulltext index with unique text".to_string(),
168                });
169                (graph, vertex_id)
170            },
171            |(mut graph, vertex_id)| {
172                graph.remove_vertex(vertex_id);
173            },
174        )
175    });
176}
177
178#[cfg(not(all(feature = "vertex-full-text-index", feature = "element-removal")))]
179pub fn bench_removal<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
180where
181    G: Graph<Vertex = Vertex, Edge = Edge>,
182{
183    // No-op when features are disabled
184}