Details
-
Improvement
-
Status: Closed
-
Major
-
Resolution: Won't Do
-
3.3.0
-
None
-
None
Description
Here, we describe a framework that puts an object-oriented spin on the Gremlin property graph. It aims to make it much easier to specify business DSLs around Gremlin.
Object Model
Every element in the property graph, whether it be a vertex (property) or an edge, is made up of properties, each of which is a String key and an arbitrary Java value. It only seems fitting then to try and represent that property as a strongly-typed Java field. The specific class in which that field is defined then becomes the vertex (property) or edge.
Let's consider the example of the person vertex, taken from the TinkerFactory. In our object world, it would be defined as a Person class that extends a Vertex class like so:
@Data @Alias(label = "person") public class Person extends Vertex { public static ToVertex KnowsPeople = traversal -> traversal .out(Label.of(Knows.class)) .hasLabel(Label.of(Person.class)); @PrimaryKey private String name; @OrderingKey private int age; private Set<String> titles; private List<Location> locations; }
The person's name and age properties become primitive fields in the class. The KnowsPeople field in this class is an example of an in-line SubTraversal, which is just a reusable function that performs certain steps on a GraphTraversal.
Its titles field, which is defined to be a Set, takes on the set cardinality. Similarly, the locations field gets the list cardinality. Since each location has it's own meta-properties, it deserves a Location class of it's own.
@Data public class Location extends Element { @OrderingKey @PropertyValue private String name; @OrderingKey private Instant startTime; private Instant endTime; }
The value of the location is stored in name, due to the placement of the @PropertyValue annotation. Every other field in that class becomes the location's meta-property.
Updating Objects
The Graph interface lets you update the graph using Vertex or Edge objects. Below, a person vertex containing a list of locations is added, along with three outgoing edges.
graph .addVertex( Person.of("marko", Location.of("san diego", 1997, 2001), Location.of("santa cruz", 2001, 2004), Location.of("brussels", 2004, 2005), Location.of("santa fe", 2005))).as("marko") .addEdge(Develops.of(2010), "tinkergraph") .addEdge(Uses.of(Proficient), "gremlin") .addEdge(Uses.of(Expert), "tinkergraph")
Since the object being added may already exist in the graph, we provide various ways to resolve "merge conflicts", such as MERGE, REPLACE, CREATE, IGNORE and INSERT.
Querying Objects
Next, let's see how to use the Query interface. The following snippet queries the graph by a chain of SubTraversals, and parses the result into a list of Person vertices.
List<Person> friends = query .by(HasKeys.of(modern.marko), Person.KnowsPeople) .list(Person.class);
Below, we query by an AnyTraversal (a function on the GraphTraversalSource), and get a single Person back.
Person marko = Person.of("marko"); Person actual = query .by(g -> g.V().hasLabel(marko.label()).has("name", marko.name())) .one(Person.class);
Service Provider Interface
To become a gremlin-objects provider, you would need to implement the GraphSystem, which supplies a GraphTraversalSource. And then, extend the ObjectGraph and ObjectQuery abstract classes, constructor injecting your GraphSystem.
For more details, please see the readme file in the the pull request that I'm about to submit, which also comes with a reference implementation based on TinkerGraph. While I also have a DataStax implementation, which we use at Elementum, a supply chain graph company, it isn't included since it depends on an older TinkerPop version.
Attachments
Issue Links
- links to