Skip to content

Commit 7001d8d

Browse files
authored
[DE-1038] demo (#10)
* created demo * CI: added demo * CI: fixed db host
1 parent 7a1f617 commit 7001d8d

File tree

6 files changed

+6364
-14
lines changed

6 files changed

+6364
-14
lines changed

.circleci/config.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ jobs:
117117
command: mvn test -Dtest.graph.type=<<parameters.graphType>> <<parameters.args>>
118118
- store_cache
119119

120+
test-demo:
121+
executor: 'j21'
122+
steps:
123+
- timeout
124+
- checkout
125+
- setup_remote_docker
126+
- start-db
127+
- load_cache
128+
- install
129+
- run:
130+
name: Run demo
131+
command: mvn compile exec:java -Dexec.mainClass="org.example.Main"
132+
working_directory: demo
133+
- store_cache
134+
120135
test-console:
121136
executor: 'j21'
122137
steps:
@@ -252,6 +267,12 @@ workflows:
252267
jobs:
253268
- test-plugin
254269

270+
test-demo:
271+
when:
272+
not: <<pipeline.parameters.docker-img>>
273+
jobs:
274+
- test-demo
275+
255276
deploy:
256277
jobs:
257278
- deploy:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ gremlin:
5454
- "e1:[a]->[b]"
5555
- "e2:[b,c]->[e,f]"
5656
driver:
57-
hosts: [ "127.0.0.1:8529" ]
57+
hosts: [ "172.28.0.1:8529" ]
5858
password: test
5959
```
6060

demo/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
<artifactId>arangodb-tinkerpop-provider</artifactId>
2121
<version>0.0.2-SNAPSHOT</version>
2222
</dependency>
23+
<dependency>
24+
<groupId>ch.qos.logback</groupId>
25+
<artifactId>logback-classic</artifactId>
26+
<version>1.5.18</version>
27+
</dependency>
2328
</dependencies>
2429

2530
<repositories>

demo/src/main/java/org/example/Main.java

Lines changed: 222 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,247 @@
1616

1717
package org.example;
1818

19+
import com.arangodb.ArangoDB;
20+
import com.arangodb.ArangoDatabase;
1921
import com.arangodb.tinkerpop.gremlin.structure.ArangoDBGraph;
2022
import com.arangodb.tinkerpop.gremlin.utils.ArangoDBConfigurationBuilder;
2123
import org.apache.commons.configuration2.Configuration;
22-
import org.apache.tinkerpop.gremlin.structure.Vertex;
24+
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
25+
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
2326

27+
import java.util.List;
28+
import java.util.Map;
29+
30+
import static org.apache.tinkerpop.gremlin.process.traversal.Order.desc;
31+
import static org.apache.tinkerpop.gremlin.process.traversal.Scope.local;
32+
import static org.apache.tinkerpop.gremlin.structure.Column.values;
33+
34+
/**
35+
* Demo program showing how to use Gremlin with ArangoDB TinkerPop provider.
36+
* Based on: Practical Gremlin: An Apache TinkerPop Tutorial by Kelvin R. Lawrence
37+
* (<a href=https://www.kelvinlawrence.net/book/PracticalGremlin.html>link</a>)
38+
*/
2439
public class Main {
2540
private static final String DB_NAME = "demo";
41+
private static final String GRAPHML_FILE = "src/main/resources/air-routes-small.graphml";
2642

43+
@SuppressWarnings("resource")
2744
public static void main(String[] args) {
45+
System.out.println("Starting ArangoDB TinkerPop Demo with Air Routes Data");
2846

29-
// create Tinkerpop Graph backed by ArangoDB
47+
//region cleanup
48+
System.out.println("Cleaning up existing database:");
49+
{
50+
ArangoDatabase db = new ArangoDB.Builder()
51+
.host("172.28.0.1", 8529)
52+
.password("test")
53+
.build()
54+
.db(DB_NAME);
55+
if (db.exists()) {
56+
db.drop();
57+
}
58+
db.arango().shutdown();
59+
}
60+
//endregion
61+
62+
// create Tinkerpop graph backed by ArangoDB
3063
Configuration conf = new ArangoDBConfigurationBuilder()
31-
.hosts("127.0.0.1:8529")
64+
.hosts("172.28.0.1:8529")
3265
.user("root")
3366
.password("test")
3467
.database(DB_NAME)
3568
.enableDataDefinition(true)
3669
.build();
37-
ArangoDBGraph g = ArangoDBGraph.open(conf);
70+
ArangoDBGraph graph = ArangoDBGraph.open(conf);
71+
GraphTraversalSource g = graph.traversal();
3872

3973
// print supported features
40-
System.out.println(g.features());
74+
System.out.println("Graph Features:");
75+
System.out.println(graph.features());
76+
77+
// Import GraphML data
78+
System.out.println("\nImporting Air Routes data from GraphML file...");
79+
{
80+
g.io(Main.GRAPHML_FILE).read().iterate();
81+
System.out.println("Data import completed.");
82+
}
83+
84+
//region Basic Gremlin Queries
85+
System.out.println("\n=== Basic Gremlin Queries ===");
86+
{
87+
System.out.println("Counting vertices and edges:");
88+
long vertexCount = g.V().count().next();
89+
long edgeCount = g.E().count().next();
90+
System.out.println(" Vertices: " + vertexCount);
91+
System.out.println(" Edges: " + edgeCount);
92+
93+
System.out.println("\nVertex labels in the graph:");
94+
g.V().label().dedup().forEachRemaining(label -> System.out.println(" " + label));
95+
96+
System.out.println("\nEdge labels in the graph:");
97+
g.E().label().dedup().forEachRemaining(label -> System.out.println(" " + label));
98+
99+
System.out.println("\nSample of 5 airports:");
100+
g.V().hasLabel("airport").limit(5).valueMap().forEachRemaining(
101+
vm -> System.out.println(" " + vm)
102+
);
103+
104+
System.out.println("\nSample of 5 routes:");
105+
g.E().hasLabel("route").limit(5).valueMap().forEachRemaining(
106+
vm -> System.out.println(" " + vm)
107+
);
108+
}
109+
//endregion
110+
111+
//region Explore airports and routes
112+
System.out.println("\n=== Exploring Airports and Routes ===");
113+
{
114+
// Count airports by region
115+
System.out.println("\nTop 5 regions by number of airports:");
116+
g.V().hasLabel("airport")
117+
.groupCount().by("region")
118+
.order(local).by(values, desc)
119+
.<Map.Entry<String, Long>>unfold().limit(5)
120+
.forEachRemaining(e ->
121+
System.out.println(" " + e.getKey() + ": " + e.getValue() + " airports"));
41122

42-
// write vertex
43-
Vertex v = g.addVertex("person");
44-
v.property("name", "Joe");
45-
v.property("age", 22);
46123

47-
// read vertex
48-
Vertex joe = g.traversal().V().has("name", "Joe").next();
49-
System.out.println("Joe's age: " + joe.property("age").value());
124+
// Find airports with most routes
125+
System.out.println("\nTop 5 airports with most outgoing routes:");
126+
g.V().hasLabel("airport")
127+
.project("airport", "code", "routes")
128+
.by("city")
129+
.by("code")
130+
.by(__.outE("route").count())
131+
.order().by("routes", desc)
132+
.limit(5)
133+
.forEachRemaining(m ->
134+
System.out.println(" " + m.get("airport") + " (" + m.get("code") + "): " + m.get("routes") + " routes"));
135+
}
136+
//endregion
50137

51-
g.close();
138+
//region Graph Algorithms
139+
System.out.println("\n=== Graph Algorithms ===");
140+
{
141+
// Degree centrality - find most connected airports
142+
System.out.println("\nTop 5 airports by degree centrality (most connections):");
143+
g.V().hasLabel("airport")
144+
.project("airport", "code", "degree")
145+
.by("city")
146+
.by("code")
147+
.by(__.bothE().count())
148+
.order().by("degree", desc)
149+
.limit(5)
150+
.forEachRemaining(m ->
151+
System.out.println(" " + m.get("airport") + " (" + m.get("code") + "): " + m.get("degree") + " connections"));
152+
153+
// Find a path between two airports
154+
System.out.println("\nFinding shortest path between Boston (BOS) and Atlanta (ATL):");
155+
156+
g.V().hasLabel("airport")
157+
.has("code", "BOS")
158+
.repeat(__.out().simplePath())
159+
.until(__.has("code", "ATL"))
160+
.limit(5)
161+
.path().by("code")
162+
.forEachRemaining(path ->
163+
System.out.println(" Path (" + (path.size() - 1) + " hops): " +
164+
String.join(" -> ", path.objects().stream().map(Object::toString).toList())));
165+
166+
// Find all airports reachable within 2 hops from London
167+
System.out.println("\nCount of the airports reachable within 2 hops from Boston (BOS):");
168+
Long count = g.V().has("code", "BOS")
169+
.repeat(__.out().simplePath())
170+
.times(2)
171+
.dedup()
172+
.count()
173+
.next();
174+
System.out.println(" " + count + " airports");
175+
}
176+
//endregion
177+
178+
//region AQL Queries
179+
System.out.println("\n=== AQL Queries ===");
180+
{
181+
// Find weighted k-shortest paths between two airports with an AQL query
182+
System.out.println("\nFinding weighted k-shortest paths between Boston (BOS) and San Francisco (SFO) with AQL query:");
183+
184+
String shortestPathQuery = """
185+
LET start = FIRST(
186+
FOR d IN tinkerpop_vertex
187+
FILTER d.code == @start
188+
RETURN d
189+
)
190+
191+
LET target = FIRST(
192+
FOR d IN tinkerpop_vertex
193+
FILTER d.code == @target
194+
RETURN d
195+
)
196+
197+
FOR path IN OUTBOUND K_SHORTEST_PATHS start TO target GRAPH tinkerpop
198+
OPTIONS { weightAttribute: 'dist' }
199+
LIMIT 5
200+
RETURN {
201+
path: path.vertices[*].code,
202+
dist: path.weight
203+
}
204+
""";
205+
206+
graph.<Map<String, ?>>aql(shortestPathQuery, Map.of(
207+
"start", "BOS",
208+
"target", "SFO"
209+
)).forEachRemaining(path ->
210+
System.out.println(" Path (dist: " + path.get("dist") + "): \t" + path.get("path")));
211+
212+
// AQL traversal to find paths between two airports with constraints on edges
213+
System.out.println("\nFinding path between Boston (BOS) and Atlanta (ATL) with max 400 km flights with AQL query:");
214+
215+
String traversalQuery = """
216+
LET start = FIRST(
217+
FOR d IN tinkerpop_vertex
218+
FILTER d.code == @start
219+
RETURN d
220+
)
221+
222+
FOR v,e,p IN 1..10 OUTBOUND start GRAPH tinkerpop
223+
PRUNE cond = e.dist > 400
224+
OPTIONS { uniqueVertices: 'path', order: 'bfs' }
225+
FILTER NOT cond
226+
FILTER v.code == @target
227+
LIMIT 5
228+
RETURN p
229+
""";
230+
231+
graph.<Map<String, ?>>aql(traversalQuery, Map.of(
232+
"start", "BOS",
233+
"target", "ATL"
234+
))
235+
.project("path", "distances", "tot")
236+
.by(__.select("vertices").unfold().values("code").fold())
237+
.by(__.select("edges").unfold().values("dist").fold())
238+
.by(__.select("edges").unfold().values("dist").sum())
239+
.forEachRemaining(it -> {
240+
@SuppressWarnings("unchecked")
241+
List<String> path = (List<String>) it.get("path");
242+
@SuppressWarnings("unchecked")
243+
List<Number> distances = (List<Number>) it.get("distances");
244+
StringBuilder sb = new StringBuilder();
245+
for (int i = 0; i < distances.size(); i++) {
246+
sb
247+
.append(path.get(i))
248+
.append(" -(")
249+
.append(distances.get(i))
250+
.append(")-> ");
251+
}
252+
sb.append(path.getLast());
253+
System.out.println(" Path (dist: " + it.get("tot") + "): \t" + sb);
254+
}
255+
);
256+
}
257+
//endregion
258+
259+
graph.close();
52260
}
261+
53262
}

0 commit comments

Comments
 (0)