You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tinkerpop.apache.org by "Karthick Sankarachary (JIRA)" <ji...@apache.org> on 2017/08/13 18:16:01 UTC

[jira] [Created] (TINKERPOP-1750) An Object Graph Mapping Framework For Gremlin

Karthick Sankarachary created TINKERPOP-1750:
------------------------------------------------

             Summary: An Object Graph Mapping Framework For Gremlin
                 Key: TINKERPOP-1750
                 URL: https://issues.apache.org/jira/browse/TINKERPOP-1750
             Project: TinkerPop
          Issue Type: Improvement
          Components: structure, tinkergraph
    Affects Versions: 3.3.0
            Reporter: Karthick Sankarachary


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.

h5. 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:

{code:java}
@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;
}
{code}

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.

{code:java}
@Data
public class Location extends Element {

  @OrderingKey
  @PropertyValue
  private String name;
  @OrderingKey
  private Instant startTime;
  private Instant endTime;
}
{code}

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.

h5. 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.

{code:java}
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")
{code}

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}}.

h5. 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.

{code:java}
List<Person> friends = query
    .by(HasKeys.of(modern.marko), Person.KnowsPeople)
    .list(Person.class);
{code}

Below, we query by an {{AnyTraversal}} (a function on the {{GraphTraversalSource}}), and get a single {{Person}} back.

{code:java}
Person marko = Person.of("marko");
Person actual = query
    .by(g -> g.V().hasLabel(marko.label()).has("name", marko.getName()))
    .one(Person.class);
{code}

h5. 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.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)