This is a convenience Gremlin Server client for Java that can send queries via a Gremlin Client
instance:
- to a remote Gremlin Server with Cypher plugin,
- with client-side translation: to a Gremlin Server-based database, Amazon Neptune, or Azure Cosmos DB.
To add a dependency using Maven:
<dependency>
<groupId>org.opencypher.gremlin</groupId>
<artifactId>cypher-gremlin-server-client</artifactId>
<version>1.0.4</version>
</dependency>
To add a dependency using Gradle:
dependencies {
compile 'org.opencypher.gremlin:cypher-gremlin-server-client:1.0.4'
}
You can also build the snapshot from source.
To send Cypher queries to a Cypher-enabled Gremlin Server and get Cypher-style results:
Cluster cluster = Cluster.open(configuration);
Client gremlinClient = cluster.connect();
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.plugin(gremlinClient);
String cypher = "MATCH (p:person) WHERE p.age > 25 RETURN p.name";
CypherResultSet resultSet = cypherGremlinClient.submit(cypher);
List<Map<String, Object>> results = resultSet.all();
Result sets can be consumed in various ways (all share the same iterator, so pick one):
List<Map<String, Object>> list = cypherGremlinClient.submit(cypher).all(); // as a list
Stream<Map<String, Object>> stream = cypherGremlinClient.submit(cypher).stream(); // as a stream
Iterator<Map<String, Object>> iterator = cypherGremlinClient.submit(cypher).iterator(); // as an iterator
Iterable<Map<String, Object>> iterable = cypherGremlinClient.submit(cypher); // also an iterable
Queries can be submitted asynchronously:
String cypher = "MATCH (p:person) WHERE p.age > 25 RETURN p.name";
CompletableFuture<CypherResultSet> future = cypherGremlinClient.submitAsync(cypher);
future
.thenApply(CypherResultSet::all)
.thenAccept(resultSet -> {
// ...
});
If the target Gremlin Server does not have the Cypher plugin installed, translation can be done on the client's thread:
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.translating(gremlinClient);
It is possible to configure statement parameters and timeout:
CypherGremlinClient client = CypherGremlinClient.plugin(gremlinClient);
List<Map<String, Object>> results = client.statement("MATCH (n) WHERE n.name=$p1 AND n.age=$p2 RETURN n")
.addParameter("p1", "marko")
.addParameter("p2", 29L)
.withTimeout(30, TimeUnit.SECONDS)
.submit()
.get().all();
A translating client for Azure Cosmos DB can be configured like so:
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.retrieving(
gremlinClient,
TranslatorFlavor.cosmosDb()
);
A translating client for Amazon Neptune can be configured like so:
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.translating(
gremlinClient,
() -> Translator.builder()
.gremlinGroovy()
.inlineParameters()
.enableMultipleLabels()
.build(TranslatorFlavor.neptune())
);
You can also execute Cypher directly against a GraphTraversalSource
:
TinkerGraph graph = TinkerFactory.createModern();
GraphTraversalSource traversal = graph.traversal();
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.inMemory(traversal);
String cypher = "MATCH (p:person) WHERE p.age > 25 RETURN p.name";
List<Map<String, Object>> results = cypherGremlinClient.submit(cypher).all();
Consult the Javadoc for more information.
If you want to use a Neo4j driver-like API, take a look at the Cypher Gremlin Neo4j Driver.
With CypherTraversalSource
its possible to combine Cypher and Gremlin in single query. Traversal can start with cypher
step that allows to run Cypher
query (which will be translated to Gremlin) then continue traversal using other Gremlin steps. Note that cypher
step returns list of maps, corresponding to rows and named columns.
To continue traversal with other Gremlin steps, use select step:
CypherTraversalSource g = graph.traversal(CypherTraversalSource.class);
GraphTraversal<Map<String, Object>, String> query = g
.cypher("MATCH (n) RETURN n")
.select("n")
.outE()
.label()
.dedup();
This approach can be used for remote databases using withRemote. Translation could be adapted for specific Gremlin implementation by passing Flavor or enabling Gremlin Extensions for Cypher:
CypherTraversalSource g = AnonymousTraversalSource
.traversal(CypherTraversalSource.class)
.withRemote(PATH_TO_REMOTE_PROPERTIES);
GraphTraversal<Map<String, Object>, String> traversal = g
.cypher("MATCH (n) RETURN n", "cosmosdb")
.select("n")
.outE()
.label()
.dedup();
Note that Cypher query may return null values, represented by string constant.
Experimental gremlin
Cypher function that allows including Gremlin steps in translated query. Note that currently
function should be enabled explicitly.
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.translating(
gremlinClient,
() -> Translator.builder()
.gremlinGroovy()
.enableCypherExtensions()
.enable(TranslatorFeature.EXPERIMENTAL_GREMLIN_FUNCTION)
.build()
);
List<Map<String, Object>> results = cypherGremlinClient.submit(
"MATCH (n:person {name: 'marko'}) " +
"RETURN gremlin(\"select('n').outE().label()\") as r").all();
For Gremlin Server set translatorFeatures: "+multiple_labels"
in opProcessor configuration