Fluent API
The driver depends on Apache TinkerPop™, a graph computing framework that provides a fluent API to build Gremlin traversals. This allows you to write your graph requests directly in Java, like you would in a Gremlin-groovy script:
// How this is initialized will depend on the execution model, see details below
GraphTraversalSource g = ...
GraphTraversal<Vertex, Vertex> traversal = g.V().has("name", "marko");
Execution models
There are two ways to execute fluent traversals:
-
explicitly by wrapping a traversal into a statement and passing it to
session.execute
; - implicitly by building the traversal from a connected source, and calling a terminal step.
Common topics
The following apply regardless of the execution model:
Limitations
At the time of writing (DSE 6.0 / driver 4.0), some types of queries cannot be executed through the fluent API:
- system queries (e.g. creating / dropping a graph);
- configuration;
- DSE graph schema queries.
You’ll have to use the script API for those use cases.
Performance considerations
Before sending a fluent graph statement over the network, the driver serializes the Gremlin traversal into a byte array. Traversal serialization happens on the client thread, even in asynchronous mode. In other words, it is done on:
- the thread that calls
session.execute
orsession.executeAsync
for explicit execution; - the thread that calls the terminal step for implicit execution.
In practice, this shouldn’t be an issue, but we’ve seen it become problematic in some corner cases
of our performance benchmarks: if a single thread issues a lot of session.executeAsync
calls in a
tight loop, traversal serialization can dominate CPU usage on that thread, and become a bottleneck
for request throughput.
If you believe that you’re running into that scenario, start by profiling your application to
confirm that the client thread maxes out its CPU core; to solve the problem, distribute your
session.executeAsync
calls onto more threads.
Domain specific languages
Gremlin can be extended with domain specific languages to make traversals more natural to write. For example, considering the following query:
g.V().hasLabel("person").has("name", "marko").
out("knows").hasLabel("person").has("name", "josh");
A “social” DSL could be written to simplify it as:
socialG.persons("marko").knows("josh");
TinkerPop provides an annotation processor to generate a DSL from an annotated interface. This is covered in detail in the TinkerPop documentation.
Once your custom traversal source is generated, here’s how to use it:
// Non-connected source for explicit execution:
SocialTraversalSource socialG = DseGraph.g.getGraph().traversal(SocialTraversalSource.class);
// Connected source for implicit execution:
SocialTraversalSource socialG =
DseGraph.g
.withRemote(DseGraph.remoteConnectionBuilder(session).build())
.getGraph()
.traversal(SocialTraversalSource.class);
Search and geospatial predicates
All the DSE predicates are available on the driver side:
-
for search, use the Search class:
GraphTraversal<Vertex, String> traversal = g.V().has("recipe", "instructions", Search.token("Saute")).values("name");
-
for geospatial queries, use the Geo class:
GraphTraversal<Vertex, String> traversal = g.V() .has( "location", "point", Geo.inside(Geo.point(2.352222, 48.856614), 4.2, Geo.Unit.DEGREES)) .values("name");