Gremlin is a Groovy based Graph Traversal Language. It provides a very expressive way of explicitly scripting traversals through a Neo4j graph.
The Neo4j Gremlin Plugin provides an endpoint to send Gremlin scripts to the Neo4j Server.
The scripts are executed on the server database and the results are returned as Neo4j Node and Relationship representations.
This keeps the types throughout the REST API consistent.
The results are quite verbose when returning Neo4j Node
,
Relationship
or Graph
representations.
On the other hand, just return properties like in the Section 6.13.4, “Send a Gremlin Script - JSON encoded with table results”
example for responses tailored to specific needs.
Scripts can be sent as URL-encoded
Raw script source
i = g.v(2) i.out
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/x-www-form-urlencoded
script=i+%3D+g.v%282%29%3Bi.out
Example response
200:
OK
Content-Type:
application/json
[ { "outgoing_relationships" : "http://localhost:7474/db/data/node/1/relationships/out", "data" : { "name" : "you" }, "traverse" : "http://localhost:7474/db/data/node/1/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/1/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/1/properties/{key}", "self" : "http://localhost:7474/db/data/node/1", "properties" : "http://localhost:7474/db/data/node/1/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/1/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/1/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/1/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/1/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/1/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/1/relationships/in/{-list|&|types}" } ]
Import a graph form a GraphML file can be achieved through the Gremlin GraphMLReader. The following script imports a small GraphML file from an URL into Neo4j, resulting in the depicted graph. It then returns a list of all nodes in the graph.
Raw script source
g.loadGraphML('https://raw.github.com/neo4j/gremlin-plugin/master/src/data/graphml1.xml') g.V
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"g.loadGraphML('https://raw.github.com/neo4j/gremlin-plugin/master/src/data/graphml1.xml');g.V;" }
Example response
200:
OK
Content-Type:
application/json
[ { "outgoing_relationships" : "http://localhost:7474/db/data/node/5/relationships/out", "data" : { "name" : "I" }, "traverse" : "http://localhost:7474/db/data/node/5/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/5/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/5/properties/{key}", "self" : "http://localhost:7474/db/data/node/5", "properties" : "http://localhost:7474/db/data/node/5/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/5/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/5/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/5/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/5/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/5/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/5/relationships/in/{-list|&|types}" }, { "outgoing_relationships" : "http://localhost:7474/db/data/node/6/relationships/out", "data" : { "name" : "you" }, "traverse" : "http://localhost:7474/db/data/node/6/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/6/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/6/properties/{key}", "self" : "http://localhost:7474/db/data/node/6", "properties" : "http://localhost:7474/db/data/node/6/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/6/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/6/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/6/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/6/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/6/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/6/relationships/in/{-list|&|types}" }, { "outgoing_relationships" : "http://localhost:7474/db/data/node/7/relationships/out", "data" : { "name" : "him" }, "traverse" : "http://localhost:7474/db/data/node/7/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/7/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/7/properties/{key}", "self" : "http://localhost:7474/db/data/node/7", "properties" : "http://localhost:7474/db/data/node/7/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/7/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/7/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/7/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/7/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/7/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/7/relationships/in/{-list|&|types}" } ]
The following script returns a sorted list
of all nodes connected via outgoing relationships
to node 1, sorted by their name
-property.
Raw script source
g.v(13).out.sort{it.name}.toList()
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"g.v(13).out.sort{it.name}.toList()" }
Example response
200:
OK
Content-Type:
application/json
[ { "outgoing_relationships" : "http://localhost:7474/db/data/node/12/relationships/out", "data" : { "name" : "him" }, "traverse" : "http://localhost:7474/db/data/node/12/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/12/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/12/properties/{key}", "self" : "http://localhost:7474/db/data/node/12", "properties" : "http://localhost:7474/db/data/node/12/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/12/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/12/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/12/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/12/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/12/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/12/relationships/in/{-list|&|types}" }, { "outgoing_relationships" : "http://localhost:7474/db/data/node/11/relationships/out", "data" : { "name" : "you" }, "traverse" : "http://localhost:7474/db/data/node/11/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/11/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/11/properties/{key}", "self" : "http://localhost:7474/db/data/node/11", "properties" : "http://localhost:7474/db/data/node/11/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/11/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/11/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/11/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/11/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/11/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/11/relationships/in/{-list|&|types}" } ]
To send a Script JSON encoded, set the payload Content-Type Header.
In this example, find all the things that my friends like,
and return a table listing my friends by their name,
and the names of the things they like in a table with two columns,
ignoring the third named step variable I
.
Remember that everything in Gremlin is an iterator - in order
to populate the result table t
, iterate through the pipes with
>> -1
.
Raw script source
i = g.v(19) t= new Table() i.as('I').out('know').as('friend').out('like').as('likes').table(t,['friend','likes']){it.name}{it.name} >> -1 t
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"i = g.v(19);t= new Table();i.as('I').out('know').as('friend').out('like').as('likes').table(t,['friend','likes']){it.name}{it.name} >> -1;t;" }
Example response
200:
OK
Content-Type:
application/json
{ "data" : [ [ "Joe", "cats" ], [ "Joe", "dogs" ] ], "columns" : [ "friend", "likes" ] }
To set variables in the bindings for the Gremlin Script
Engine on the server, you can include a params
parameter
with a String representing a JSON map of variables to set
to initial values. These can then be accessed as normal
variables within the script.
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"meaning_of_life", "params":{ "meaning_of_life" : 42.0 } }
Example response
200:
OK
Content-Type:
application/json
42.0
Send a Gremlin Script, as JSON payload and additional parameters
Raw script source
g.v(me).out
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script" : "g.v(me).out", "params" : { "me" : 4 } }
Example response
200:
OK
Content-Type:
application/json
[ { "outgoing_relationships" : "http://localhost:7474/db/data/node/3/relationships/out", "data" : { "name" : "you" }, "traverse" : "http://localhost:7474/db/data/node/3/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/3/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/3/properties/{key}", "self" : "http://localhost:7474/db/data/node/3", "properties" : "http://localhost:7474/db/data/node/3/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/3/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/3/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/3/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/3/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/3/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/3/relationships/in/{-list|&|types}" } ]
The following script returns a sorted list
of all nodes connected via outgoing relationships
to node 1, sorted by their name
-property.
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"g.v(16).out.name.paths" }
Example response
200:
OK
Content-Type:
application/json
[ "[v[16], v[14], you]", "[v[16], v[15], him]" ]
This example demonstrates that you via the Groovy runtime embedded with the server have full access to all of the servers Java APIs. The below example creates Nodes in the database both via the Blueprints and the Neo4j API indexes the nodes via the native Neo4j Indexing API constructs a custom Lucene sorting and searching returns a Neo4j IndexHits result iterator.
Raw script source
import org.neo4j.graphdb.index.* import org.neo4j.index.lucene.* import org.apache.lucene.search.* neo4j = g.getRawGraph() tx = neo4j.beginTx() meVertex = g.addVertex([name:'me']) meNode = meVertex.getRawVertex() youNode = neo4j.createNode() youNode.setProperty('name','you') idxManager = neo4j.index() personIndex = idxManager.forNodes('persons') personIndex.add(meNode,'name',meVertex.name) personIndex.add(youNode,'name',youNode.getProperty('name')) tx.success() tx.finish() query = new QueryContext( 'name:*' ).sort( new Sort(new SortField( 'name',SortField.STRING, true ) ) ) results = personIndex.query( query )
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"import org.neo4j.graphdb.index.*;import org.neo4j.index.lucene.*;import org.apache.lucene.search.*;neo4j = g.getRawGraph();tx = neo4j.beginTx();meVertex = g.addVertex([name:'me']);meNode = meVertex.getRawVertex();youNode = neo4j.createNode();youNode.setProperty('name','you');idxManager = neo4j.index();personIndex = idxManager.forNodes('persons');personIndex.add(meNode,'name',meVertex.name);personIndex.add(youNode,'name',youNode.getProperty('name'));tx.success();tx.finish();query = new QueryContext( 'name:*' ).sort( new Sort(new SortField( 'name',SortField.STRING, true ) ) );results = personIndex.query( query );" }
Example response
200:
OK
Content-Type:
application/json
[ { "outgoing_relationships" : "http://localhost:7474/db/data/node/22/relationships/out", "data" : { "name" : "you" }, "traverse" : "http://localhost:7474/db/data/node/22/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/22/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/22/properties/{key}", "self" : "http://localhost:7474/db/data/node/22", "properties" : "http://localhost:7474/db/data/node/22/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/22/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/22/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/22/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/22/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/22/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/22/relationships/in/{-list|&|types}" }, { "outgoing_relationships" : "http://localhost:7474/db/data/node/21/relationships/out", "data" : { "name" : "me" }, "traverse" : "http://localhost:7474/db/data/node/21/traverse/{returnType}", "all_typed_relationships" : "http://localhost:7474/db/data/node/21/relationships/all/{-list|&|types}", "property" : "http://localhost:7474/db/data/node/21/properties/{key}", "self" : "http://localhost:7474/db/data/node/21", "properties" : "http://localhost:7474/db/data/node/21/properties", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/21/relationships/out/{-list|&|types}", "incoming_relationships" : "http://localhost:7474/db/data/node/21/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/21/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/21/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/21/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/21/relationships/in/{-list|&|types}" } ]
Exporting a graph can be done by simple emitting the appropriate String.
Raw script source
writer = new GraphMLWriter(g) out = new java.io.ByteArrayOutputStream() writer.outputGraph(out) result = out.toString()
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"writer = new GraphMLWriter(g);out = new java.io.ByteArrayOutputStream();writer.outputGraph(out);result = out.toString();" }
Example response
200:
OK
Content-Type:
application/json
"<?xml version=\"1.0\" ?><graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"><key id=\"name\" for=\"node\" attr.name=\"name\" attr.type=\"string\"></key><graph id=\"G\" edgedefault=\"directed\"><node id=\"8\"><data key=\"name\">you</data></node><node id=\"9\"><data key=\"name\">him</data></node><node id=\"10\"><data key=\"name\">I</data></node><edge id=\"4\" source=\"10\" target=\"8\" label=\"know\"></edge><edge id=\"5\" source=\"10\" target=\"9\" label=\"know\"></edge></graph></graphml>"
Imagine a user being part of different groups.
A group can have different roles, and a user can
be part of different groups. He also can
have different roles in different groups apart
from the membership.
The association of a User, a Group and a Role can
be referred to as a HyperEdge. However, it can be easily modeled
in a property graph as a node that captures this n-ary
relationship, as depicted below in the U1G2R1
node.
To find out in what roles a user is for a particular groups (here Group2), the following script can traverse this HyperEdge node and provide answers.
Raw script source
g.v(29).out('hasRoleInGroup').as('hyperedge').out('hasGroup').filter{it.name=='Group2'}.back('hyperedge').out('hasRole').name
Final Graph:
Example request
POST
http://localhost:7474/db/data/ext/GremlinPlugin/graphdb/execute_script
Accept:
application/json
Content-Type:
application/json
{ "script":"g.v(29).out('hasRoleInGroup').as('hyperedge').out('hasGroup').filter{it.name=='Group2'}.back('hyperedge').out('hasRole').name" }
Example response
200:
OK
Content-Type:
application/json
[ "Role1" ]
Copyright © 2011 Neo Technology