You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2017/05/26 12:24:10 UTC

[19/41] tinkerpop git commit: TINKERPOP-786 Added some initial documentation for DSLs

TINKERPOP-786 Added some initial documentation for DSLs


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/50f2dac9
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/50f2dac9
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/50f2dac9

Branch: refs/heads/master
Commit: 50f2dac9d897d5776a2cdd4ae3a7b56a4ed6339a
Parents: e661359
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue May 9 13:57:48 2017 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue May 16 11:01:51 2017 -0400

----------------------------------------------------------------------
 docs/src/reference/the-traversal.asciidoc | 154 +++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/50f2dac9/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 2612309..1be365d 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -2939,3 +2939,157 @@ g.V().outE().inV().
     by().
     by('name')
 ----
+
+[[dsl]]
+Domain Specific Languages
+-------------------------
+
+Gremlin is a link:http://en.wikipedia.org/wiki/Domain-specific_language[domain specific language] (DSL) for traversing
+graphs. It operates in the language of vertices, edges and properties. Typically, applications built with Gremlin are
+not of the graph domain, but instead model their domain within a graph. For example, the "modern" toy graph models
+software and person domain objects with the relationships between them (i.e. a person "knows" another person and a
+person "created" software).
+
+image::tinkerpop-modern.png[width=350]
+
+An analyst who wanted to find all the people who "marko" knows could write the following Gremlin:
+
+[source,java]
+----
+g.V().hasLabel('person').has('name','marko').out('knows')
+----
+
+While this method achieves the desired answer, it requires the analyst to traverse the graph in the domain language
+of the graph rather than the domain language of the social network. A more natural way for the analyst to write this
+traversal might be:
+
+[source,java]
+----
+g.persons('marko').knows()
+----
+
+In the statement above, the traversal is written in the language of the domain, abstracting away the underlying
+graph structure from the query. The two traversal results are equivalent and, indeed, the "Social Network DSL" produces
+the same set of traversal steps as the "Graph DSL" thus producing equivalent strategy application and performance
+runtimes.
+
+The following sections explain how to develop application specific DSLs for different <<gremlin-variants,Gremlin Language Variants>>.
+
+[[gremlin-java-dsl]
+Gremlin-Java
+~~~~~~~~~~~~
+
+Creating a DSL in Java requires the `@GremlinDsl` Java annotation in `gremlin-core`. This annotation should be applied
+to a "DSL interface" that extends `GraphTraversal.Admin`.
+
+[source,java]
+----
+@GremlinDsl
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+}
+----
+
+IMPORTANT: The name of the DSL interface should be suffixed with "TraversalDSL". All characters in the interface name
+before that become the "name" of the DSL.
+
+In this interface, define the methods that the DSL will be composed of:
+
+[source,java]
+----
+@GremlinDsl
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+    public default GraphTraversal<S, Vertex> knows(String personName) {
+        return out("knows").hasLabel("person").has("name", personName);
+    }
+
+    public default <E2 extends Number> GraphTraversal<S, E2> youngestFriendsAge() {
+        return out("knows").hasLabel("person").values("age").min();
+    }
+}
+----
+
+The `@GremlinDsl` annotation is used by the link:https://docs.oracle.com/javase/8/docs/api/index.html?javax/annotation/processing/Processor.html[Java Annotation Processor]
+to generate the boilerplate class structure required to properly use the DSL within the TinkerPop framework. These
+classes can be generated and maintained by hand, but it would be time consuming, monotonous and error-prone to do so.
+Typically, the Java compilation process is automatically configured to detect annotation processors on the classpath
+and will automatically use them when found. If that does not happen, it may be necessary to make configuration changes
+to the build to allow for the compilation process to be aware of the following `javax.annotation.processing.Processor`
+implementation:
+
+[source,java]
+----
+org.apache.tinkerpop.gremlin.process.traversal.dsl.GremlinDslProcessor
+----
+
+The annotation processor will generate several classes for the DSL:
+
+* `SocialTraversal` - A `Traversal` interface that extends the `SocialTraversalDsl` proxying methods to its underlying
+interfaces (such as `GraphTraversal`) to instead return a `SocialTraversal`
+* `DefaultSocialTraversal` - A default implementation of `SocialTraversal` (typically not used directly by the user)
+* `SocialTraversalSource` - Spawns `DefaultSocialTraversal` instances.
+
+Using the DSL then just involves telling the `Graph` to use it:
+
+[source,java]
+----
+SocialTraversalSource social = graph.traversal(SocialTraversalSource.class);
+social.V().has("name","marko").knows("josh");
+----
+
+The `SocialTraversalSource` can also be customized with DSL functions. As an additional step, include a class that
+extends from `GraphTraversalSource` and with a name that is suffixed with "TraversalSourceDsl". Include in this class,
+any custom methods required by the DSL:
+
+[source,java]
+----
+public class SocialTraversalSourceDsl extends GraphTraversalSource {
+
+    public SocialTraversalSourceDsl(final Graph graph, final TraversalStrategies traversalStrategies) {
+        super(graph, traversalStrategies);
+    }
+
+    public SocialTraversalSourceDsl(final Graph graph) {
+        super(graph);
+    }
+
+    public GraphTraversal<Vertex, Vertex> persons(String... names) {
+        GraphTraversalSource clone = this.clone();
+
+        // Manually add a "start" step for the traversal in this case the equivalent of V(). GraphStep is marked
+        // as a "start" step by passing "true" in the constructor.
+        clone.getBytecode().addStep(GraphTraversal.Symbols.V);
+        GraphTraversal<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(clone);
+        traversal.asAdmin().addStep(new GraphStep<>(traversal.asAdmin(), Vertex.class, true));
+
+        traversal = traversal.hasLabel("person");
+        if (names.length > 0) traversal = traversal.has("name", P.within(names));
+
+        return traversal;
+    }
+}
+----
+
+Then, back in the `SocialTraversal` interface, update the `GremlinDsl` annotation with the `traversalSource` argument
+to point to the fully qualified class name of the `SocialTraversalSourceDsl`:
+
+[source,java]
+----
+@GremlinDsl(traversalSource = "com.company.SocialTraversalSourceDsl")
+public interface SocialTraversalDsl<S, E> extends GraphTraversal.Admin<S, E> {
+    ...
+}
+----
+
+It is then possible to use the `persons()` method to start traversals:
+
+[source,java]
+----
+SocialTraversalSource social = graph.traversal(SocialTraversalSource.class);
+social.persons().count();
+----
+
+NOTE: Using Maven, as shown in the `gremlin-archetype-dsl` module, makes developing DSLs with the annotation processor
+straightforward in that it sets up appropriate paths to the generated code automatically.
+
+Gremlin-Python
+~~~~~~~~~~~~~~