Cypher for Gremlin
oCIM 4 Apache TinkerPop
Apache TinkerPop™ is a graph computing framework for both graph databases (OLTP) and graph analytic systems (OLAP).
Gremlin is a graph traversal language developed by Apache TinkerPop. Gremlin in the wild Gremlin in the wild
IBM Graph Gremlin in the wild
IBM Graph Gremlin in the wild
IBM Graph Azure Cosmos DB Gremlin in the wild
IBM Graph Azure Cosmos DB
Amazon Neptune Gremlin language
gremlin> g.V().count() ==>0 gremlin> g.addV('City').property('name', 'København') gremlin> g.V().count() ==>1 gremlin> g.V().hasLabel('City').values('name') ==>København Declarative vs imperative querying
// Cypher: what to get MATCH (b:Boat)-[:SAILS_TO]->(:Location {name: 'Denmark'}) RETURN b
// Gremlin: how to get it g.V().hasLabel('Boat').as('b') .out('SAILS_TO') .hasLabel('Location').has('name', 'Denmark') .select('b') Gremlin traversal g.V().hasLabel('Boat').as('b') .out('SAILS_TO') .hasLabel('Location').has('name', 'Denmark') .select('b') .profile()
Step Count
TinkerGraphStep(vertex,[~label.eq(Boat)])@[b] 100000
VertexStep(OUT,[SAILS_TO],vertex) 100000
HasStep([~label.eq(Location), name.eq(Denmark)]) 1
SelectOneStep(last,b) 1 Gremlin traversal (the right way) g.V().hasLabel('Location').has('name', 'Denmark') .in('SAILS_TO') .hasLabel('Boat') .profile()
Step Count
TinkerGraphStep(vertex,[~label.eq(Location), name.eq(Denmark)]) 1
VertexStep(IN,[SAILS_TO],vertex) 1
HasStep([~label.eq(Boat)]) 1 Cypher in Gremlin
// MATCH (b:Boat)-[:SAILS_TO]->(:Location {name: 'Denmark'}) // RETURN b.name g.V().hasLabel('Boat').as('b') .out('SAILS_TO') .hasLabel('Location').has('name', 'Denmark') .select('b').values('name')
==>"Havhingsten fra Glendalough" ==>"Roar Ege" Cypher in Gremlin: return columns
// MATCH (b:Boat)-[:SAILS_TO]->(:Location {name: 'Denmark'}) // RETURN b.name g.V().hasLabel('Boat').as('b') .out('SAILS_TO') .hasLabel('Location').has('name', 'Denmark') .select('b').project('b.name').by(values('name'))
==>{"b.name": "Havhingsten fra Glendalough"} ==>{"b.name": "Roar Ege"} Null handling in Gremlin
gremlin> g.addV('Boat').property('name', 'Roar Ege') ==>v[0] gremlin> g.addV('Boat') ==>v[1] gremlin> g.V().count() ==>2 gremlin> g.V().hasLabel('Boat').values('name') ==>Roar Ege gremlin> g.V().hasLabel('Boat').project('name').by(values('name')) ==>[name:Roar Ege] The provided traverser does not map to a value: v[5]->[PropertiesStep([name],value)] Cypher in Gremlin: nulls
// MATCH (b:Boat)-[:SAILS_TO]->(:Location {name: 'Denmark'}) // RETURN b.name g.V().hasLabel('Boat').as('b') .out('SAILS_TO') .hasLabel('Location').has('name', 'Denmark') .select('b').project('b.name').by( choose(neq('NULL'), coalesce(values('name'), constant('NULL')), constant('NULL'))) Cypher in Gremlin: traversal-based logic
// RETURN $a AND $b g.inject('START').project('$a AND $b').by( choose( and(constant(a).is(eq(true)), constant(b).is(eq(true))), constant(true), choose( or(constant(a).is(eq(false)), constant(b).is(eq(false))), constant(false), constant('NULL')))) Translation flow Cypher TCK progress
82.5% 731 scenarios
(with Server plugin) Major limitations
● Functionality exclusive to Gremlin Servers with Cypher plugin:
○ List access by non-constant index ○ Map access ○ Non-numeric plus operator ○ Path comprehensions ○ Functions with non-native implementation: length, nodes, percentileCont, percentileDisc, properties, relationships, size, toBoolean, toFloat, toInteger, toString ● Multiple labels and label modification are not supported
○ TinkerPop graph elements have a single, immutable string label ○ No plans for a workaround Cypher for Gremlin integration
Gremlin Server Gremlin Server
without Cypher plugin with Cypher plugin
Gremlin driver ❌ ✔ server-side translation
Cypher Gremlin client ✔ client-side translation ✔ server-side translation for Java
Gremlin Console ❌ ❌
Gremlin Console ✔ client-side translation ✔ server-side translation with Cypher plugin It’s on GitHub!
https://github.com/opencypher/cypher-for-gremlin It’s on GitHub!
● Cypher to Gremlin translation library for Java ● Cypher plugin for Gremlin Server ● Cypher plugin for Gremlin Console ● Cypher wrapper for Gremlin client ● Neo4j driver API wrapper ● TCK implementation for Gremlin
https://github.com/opencypher/cypher-for-gremlin Java APIs: translation
String cypher = "MATCH (p:Person) WHERE p.age > 25 RETURN p.name"; CypherAstWrapper ast = CypherAstWrapper.parse(cypher);
Translator
Cluster cluster = Cluster.open(configuration); Client gremlinClient = cluster.connect(); CypherGremlinClient cypherGremlinClient = CypherGremlinClient.translating(gremlinClient);
String cypher = "MATCH (p:person) WHERE p.age > 25 RETURN p.name"; CypherResultSet resultSet = cypherGremlinClient.submit(cypher); List
Config config = Config.build() .withTranslation() .toConfig(); Driver driver = GremlinDatabase.driver("//localhost:8182", config);
String cypher = "MATCH (p:person) WHERE p.age > 25 RETURN p.name"; try (Session session = driver.session()) { StatementResult result = session.run(cypher); List
TinkerGraph graph = TinkerFactory.createModern(); GraphTraversalSource traversal = graph.traversal();
// Gremlin Server client CypherGremlinClient cypherGremlinClient = CypherGremlinClient.inMemory(traversal);
// Neo4j driver Driver driver = GremlinDatabase.driver(traversal); Java APIs: In-memory graphs
// SimpleGraph Excel ExcelSystem excelSystem = new ExcelSystem(); excelSystem.connect(); excelSystem.moveTo(new File("graph.xlsx").toURI().toString()); GraphTraversalSource traversal = excelSystem.g();
CypherGremlinClient cypherGremlinClient = CypherGremlinClient.inMemory(traversal); Quick start
// Add dependencies compile "org.apache.tinkerpop:tinkergraph-gremlin:3.3.2" compile "org.opencypher.gremlin:cypher-gremlin-neo4j-driver:0.9.6"
// Create an in-memory graph TinkerGraph graph = TinkerFactory.createModern(); GraphTraversalSource traversal = graph.traversal(); Driver driver = GremlinDatabase.driver(traversal);
// Query as usual: driver.session()... etc // (Except transactions)