Gremlin is a functional, data-flow language that enables users to succinctly express complex traversals on (or queries of) their application's property graph. It hides the details of backend database implementation (like azure cosmosdb support Graph API).
Apache Tinkerpop gremlin java driver allows you to launch gremlin query, but it is not easy to get familiar with gremlin syntax. You have to generate all gremlin queries by yourself as following.
static final String[] gremlinQueries = new String[] {
"g.V().drop()",
"g.addV('person').property('id', '1').property('name', 'pli').property('age', 31)",
"g.addV('person').property('id', '4').property('name', 'incarnation').property('age', 27)",
"g.addV('software').property('id', '2').property('name', 'spring-boot-sample').property('lang', 'java')",
"g.V('1').addE('created').to(g.V('2')).property('weight', 0.8)",
"g.V('1').addE('contributed').to(g.V('2')).property('weight', 0.1)",
"g.V('4').addE('contributed').to(g.V('2')).property('weight', 0.4)"
};We'd like to make things easier by hiding the process of mapping Java instance to graph database persistent entity, with the help of spring-data-commons.
How do users use graph db? They can use gremlin driver to generate the query literal in Java class instance. It's not impossible but yet isn't easy. We want to figure out a more Spring natural way by leveraging Spring annotations to map Java instance to database entity.
As we know, there may be some concept like Vertex, Edge and Graph when we talk about
graph. Naturally the object instance needs to be mapped to one and the only one of these
element in graph. Simply we add some annotations to reach this.
@Vertex // maps an Object to a Vertex
@VertexSet // maps a set of Vertex in Graph
@Edge // maps an Object to an Edge
@EdgeSet // maps to a set of Edge in Graph
@EdgeFrom // maps to the head Vertex of an Edge
@EdgeTo // maps to the tail Vertex of an Edge
@Graph // maps to an Object to a GraphThe @GremlinRepository extends @CrudReposiotry is providing basic queries, like insert,
save, find, delete and count. Let's take insert as example to the details of implementation.
- Gremlin describes the
VertexandEdgein a flat layout, with fixed propertyid,label, and any other properties organized as key-value pair. - Gremlin properties name must be
String, and values can beNumber,BooleanandString. - No nested structure in
VertexandEdge. Edgeis directed.
Before we start to insert a Vertex instance to database, we need one abstract layer into
isolate the dependency between instance and entity in database. We define one class to
represent all instance stored in database. This class not only needs to hold all information from
instance object, but also has the flat structure like entity in database. It is the bridge between
instance in java and persistent entity in database. Here we call it GremlinSource.
With the above constriction of gremlin, GremlinSource has field id and label for mapping,
and keep all other fields into one Map<String, Object>. When we try to insert a instance from
java to GremlinSource, we perform a WRITE operation and convert the instance to a GremlinSource.
Operation WRITE will convert all the data of one instance to GremlinSource, and take care of
id or @Id field.
The GremlinSourceWriter converts Java instance to GremlinSource.
There must be one READ operation for retrieving instance from database entity. For example,
the find query will return the persistent data from database with the type Result, provided
by apache SDK. For insulating the dependency between instance and Result, just like what we do
in WRITE. We also use GremlinSource as the bridge from Result to instance. Simply there
are two steps after query from database. First the Result from database will be converted to
GremlinSource. And then the GremlinSource will be converted to Java instance, just like what
we do in WRITE operation.
The GremlinResultReader converts Result to GremlinSource.
The GremlinSourceReader converts GremlinSource to Java instance.
GremlinScript will generate the query based on GremlinSource. It converts the data like
id, label and properites into gremlin query literal Strings. For type String, Number
and Boolean, the query will store them as primitive types (supported by gremlin). And any
other type of instance field will be converted to Json-like String except type Date, it will
be converted to milliSeconds and stored as Number. Then the gremlin client will execute the query
to access database.
The GremlinScriptLiteral generates literal query based on GremlinSource.