Difference between revisions of "Gremlin"

From BITPlan Wiki
Jump to navigation Jump to search
Line 108: Line 108:
 
|template=StepRow
 
|template=StepRow
 
|userparam=row
 
|userparam=row
 +
|named args=yes
 
|sort=Step name
 
|sort=Step name
 
|order=ascending
 
|order=ascending

Revision as of 14:22, 27 April 2019

Gremlin programming language.png

Gremlin is the graph traversal language of Apache TinkerPop. Gremlin is a functional, data-flow language that enables users to succinctly express complex traversals on (or queries of) their application's property graph. Every Gremlin traversal is composed of a sequence of (potentially nested) steps. A step performs an atomic operation on the data stream. Every step is either a map-step (transforming the objects in the stream), a filter-step (removing objects from the stream), or a sideEffect-step (computing statistics about the stream). The Gremlin step library extends on these 3-fundamental operations to provide users a rich collection of steps that they can compose in order to ask any conceivable question they may have of their data for Gremlin is Turing Complete.

Explaining Gremlin

There are different levels on which gremlin can be explained:

  1. Mathematical background as explained in Marko Rodriguez's paper The Gremlin Graph Traversal Machine and Language
  2. Generic API as explained in the Tinkerpop documentation
  3. Specific API (Java) as explained in the Javadocs page
  4. Specific "modern" Example mostly used for tests and explanations regarding Gremlin

On this page the goal is to cover all 4 levels with a focus on Java being applied to the modern example. The source code TestSteps.java is available on github.

Graph

A Graph G= (V, E) consist of a finite set of vertices V and a finite set of edges E ⊆ V×V.

An Element of a Graph is either a vertice or an edge.

A Propertygraph allows all elements (vertice or edge) of a graph to have properties. Each property is a name/value pair.

The Modern example

The "modern" graph is shipped with gremlin as a standard example. tinkerpop-modern.png

The graph has 6 edges and 6 vertices.

It consists of :

  1. vertice person (name: marko, age:29)
  2. vertice person (name: vadas, age:27)
  3. vertice software (name: lop, lang: java)
  4. vertice person (name: josh, age:32)
  5. vertice software (name: ripple, lang: java)
  6. vertice person (name: peter, age:35)
  7. edge knows 1->2 (weight: 0.5)
  8. edge knows 1->4 (weight: 1.0)
  9. edge created 1->3 (weight: 0.4)
  10. edge created 4->5 (weight: 1.0)
  11. edge created 4->3 (weight: 0.4)
  12. edge created 6->3 (weight: 0.2)

In Gremlin edges and vertices have a set of properties. Each property is a name/value pair. One important property is the id of a vertice or edge. E.g. the vertice for peter has the id 6 and a property with the name "age" and the value 35 and another property with the name "name" and the value "peter".

GraphTraversal

One of the core concepts of tinkerpop/gremlin is the GraphTraversal It's interface has a generic definition as:

public interface GraphTraversal<S,E> extends Traversal<S,E>

and at https://markorodriguez.com/ the Author Marko Rodriguez explains the ideas behind using an generic approach vor handling Graphs. The Java implementation is available on github.

S is a generic Start class, and E is a generic End class as explained in the Apache Tinkerpop documentation.

GraphTraversalSource

A Graph Traversal Source is the starting point for working with a graph. The convention is to name this starting point

g

or

g()

In our tests we'll use a GraphTraversalSource for the modern example

  /**
   * common access to GraphTraversalSource
   * @return - the graph traversal
   */
  public GraphTraversalSource g() {
    Graph graph = TinkerFactory.createModern();
    GraphTraversalSource g = graph.traversal();
    return g;
  }


JUnit Testcase

  @Test
  public void testTraversal() {
    assertEquals(6,g().E().count().next().longValue());
    assertEquals(6,g().V().count().next().longValue());
  }

E() gives you access to the edges of a graph traversal. V() gives you access to the vertices of a graph traversal. In the above example we simply count the edges and vertices and check our assumption that there are 6 edges and 6 vertices in the modern example graph.

Steps

As explained in Gremlin_Basics: "The Gremlin graph traversal language defines approximately 30 steps which can be understood as the instruction set of the Gremlin traversal machine.

A regular computer has a CPU with an Instruction Pointer which tells the machine to take the instruction at that memory address and execute it next. There are also instructions that can manipulate the instruction pointer with the effect of the return from a function or a goto to a different part of the program.

Gremlin instead works on a sequence of steps and each step the "graph traversal machine" will take it's current state and execute the step to reach a new state of affairs.

The gremlin steps are useful in practice, with typically only 10 or so of them being applied in the majority of cases. Each of the provided steps can be understood as being a specification of one of the 5 general types enumerated below". step-types.png

Alphabetical table of Steps

There are 58 Steps described on this page

|- |addE |sideEffect |[http://tinkerpop.apache.org/docs/current/reference/#addedge-step addedge-step addedge-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addE-java.lang.String- addE-java.lang.String- addE] |is used to add edges to the graph |-|- |addV |sideEffect |[http://tinkerpop.apache.org/docs/current/reference/#addvertex-step addvertex-step addvertex-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV-java.lang.String- addV-java.lang.String- addV] |is used to add vertices to the graph |-|- |aggregate |sideEffect |[http://tinkerpop.apache.org/docs/current/reference/#aggregate-step aggregate-step aggregate-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate-java.lang.String- aggregate-java.lang.String- aggregate] |is used to aggregate all the objects at a particular point of traversal into a Collection |-|- |and |filter |[http://tinkerpop.apache.org/docs/current/reference/#and-step and-step and-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#and-org.apache.tinkerpop.gremlin.process.traversal.Traversal...- and-org.apache.tinkerpop.gremlin.process.traversal.Traversal...- and] |ensures that all provided traversals yield a result |-|- |as |modulator |[http://tinkerpop.apache.org/docs/current/reference/#as-step as-step as-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#as-java.lang.String-java.lang.String...- as-java.lang.String-java.lang.String...- as] |is not a real step, but a "step modulator" similar to by() and option(). With as(), it is possible to provide a label to the step that can later be accessed by steps and data structures that make use of such labels — e.g., select(), match(), and path |-|- |both |flatMap | | |maps the current elements to the vertices at the boths ends of the edges. |-|- |bothE |flatMap | | |maps the current elements to both the in and outgoing edges. |-|- |bothV |flatMap | | |maps the current edges to both the ingoing and outgoing Vertices. |-|- |branch |general |[http://tinkerpop.apache.org/docs/current/reference/#general-steps general-steps general-steps] | |Splits the traverser |-|- |by |modulator |[http://tinkerpop.apache.org/docs/current/reference/#by-step by-step by-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#by-- by-- by] |is not an actual step, but instead is a "step-modulator" similar to as() and option(). If a step is able to accept traversals, functions, comparators, etc. then by() is the means by which they are added. The general pattern is step().by()…by(). Some steps can only accept one by() while others can take an arbitrary amount. |-|- |cap |barrier |[http://tinkerpop.apache.org/docs/current/reference/#cap-step cap-step cap-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#cap-java.lang.String-java.lang.String...- cap-java.lang.String-java.lang.String...- cap] |Iterates the traversal up to the itself and emits the side-effect referenced by the key. If multiple keys are supplied then the side-effects are emitted as a Map. |-|- |choose |branch |[http://tinkerpop.apache.org/docs/current/reference/#choose-step choose-step choose-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#choose-java.util.function.Function-,choose-java.util.function.Predicate-org.apache.tinkerpop.gremlin.process.traversal.Traversal- choose-java.util.function.Function-,choose-java.util.function.Predicate-org.apache.tinkerpop.gremlin.process.traversal.Traversal- choose] |routes the current traverser to a particular traversal branch option. With choose(), it is possible to implement if/then/else-semantics as well as more complicated selections. |-|- |coalesce |flatMap |[http://tinkerpop.apache.org/docs/current/reference/#coalesce-step coalesce-step coalesce-step] | |The coalesce()-step evaluates the provided traversals in order and returns the first traversal that emits at least one element. |-|- |coin |filter |[http://tinkerpop.apache.org/docs/current/reference/#coin-step coin-step coin-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#coin-double- coin-double- coin] |randomly filters out traversers with the given probability |-|- |count |reducing barrier |[http://tinkerpop.apache.org/docs/current/reference/#count-step count-step count-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#count-- count-- count] |counts the total number of represented traversers in the streams (i.e. the bulk count). |-|- |emit |modulator |[http://tinkerpop.apache.org/docs/current/reference/#emit-step emit-step emit-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#emit-- emit-- emit] |is not an actual step, but is instead a step modulator for repeat() (find more documentation on the emit() there). |-|- |explain |terminal |[http://tinkerpop.apache.org/docs/current/reference/#terminal-steps terminal-steps terminal-steps] | |will return a TraversalExplanation. A traversal explanation details how the traversal (prior to explain()) will be compiled given the registered traversal strategies. A TraversalExplanation has a toString() representation with 3-columns. The first column is the traversal strategy being applied. The second column is the traversal strategy category: [D]ecoration, [O]ptimization, [P]rovider optimization, [F]inalization, and [V]erification. Finally, the third column is the state of the traversal post strategy application. The final traversal is the resultant execution plan. |-|- |fill |terminal |[http://tinkerpop.apache.org/docs/current/reference/#terminal-steps terminal-steps terminal-steps] | |fill(collection) will put all results in the provided collection and return the collection when complete. |-|- |filter |general |[http://tinkerpop.apache.org/docs/current/reference/#general-steps general-steps general-steps] | |Continues processing based on the given filter condition. |-|- |flatMap |general |[http://tinkerpop.apache.org/docs/current/reference/#general-steps general-steps general-steps] | |transforms the current step in a one to many fashion. |-|- |fold |reducing barrier |[http://tinkerpop.apache.org/docs/current/reference/#fold-step fold-step fold-step] | |There are situations when the traversal stream needs a "barrier" to aggregate all the objects and emit a computation that is a function of the aggregate. The fold()-step (map) is one particular instance of this. Please see unfold()-step for the inverse functionality. |-|- |has |filter |[http://tinkerpop.apache.org/docs/current/reference/#has-step has-step has-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#has-java.lang.String- has-java.lang.String- has] |filters vertices, edges, and vertex properties based on their properties. This step has quite a few variations. |-|- |hasNext |terminal |[http://tinkerpop.apache.org/docs/current/reference/#terminal-steps terminal-steps terminal-steps] | |determines whether there are available results |-|- |id |map |[http://tinkerpop.apache.org/docs/current/reference/#id-step id-step id-step] | |maps the traversal to the ids of the current elements. |-|- |in |flatMap | | |maps the current elements to the vertices at the end of the ingoing edges. |-|- |inE |flatMap | | |maps the current elements to the the ingoing edges. |-|- |inV |flatMap | | |maps the current edges to the the ingoing Vertices. |-|- |is |filter |[http://tinkerpop.apache.org/docs/current/reference/#is-step is-step is-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#is-org.apache.tinkerpop.gremlin.process.traversal.P- is-org.apache.tinkerpop.gremlin.process.traversal.P- is] |filters elements that fullfill the given predicate. Variant: Filters elements that are equal to the given Object. |-|- |iterate |terminal |[http://tinkerpop.apache.org/docs/current/reference/#terminal-steps terminal-steps terminal-steps] | |Iterates the traversal presumably for the generation of side-effects. See https://stackoverflow.com/questions/47403296/iterate-step-is-used-in-the-end-of-the-command-when-creating-nodes-and-edges-t |-|- |label |map |[http://tinkerpop.apache.org/docs/current/reference/#label-step label-step label-step] | |maps the traversal to the labels of the current elements. |-|- |limit |filter |[http://tinkerpop.apache.org/docs/current/reference/#limit-step limit-step limit-step] | | |-|- |map |general |[http://tinkerpop.apache.org/docs/current/reference/#general-steps general-steps general-steps] | |transforms the current step element to a new element (which may be empty). see also https://stackoverflow.com/questions/51015636/in-gremlin-how-does-map-really-work |-|- |match |map |[http://tinkerpop.apache.org/docs/current/reference/#match-step match-step match-step] | |see https://stackoverflow.com/questions/55609832/is-threre-a-document-about-how-gremlin-match-works |-|- |max |reducing barrier |[http://tinkerpop.apache.org/docs/current/reference/#max-step max-step max-step] | |operates on a stream of comparable objects and determines which is the last object according to its natural order in the stream. |-|- |mean |reducing barrier |[http://tinkerpop.apache.org/docs/current/reference/#mean-step mean-step mean-step] | |operates on a stream of numbers and determines the average of those numbers. |-|- |min |reducing barrier |[http://tinkerpop.apache.org/docs/current/reference/#min-step min-step min-step] | |operates on a stream of comparable objects and determines which is the first object according to its natural order in the stream. |-|- |next |terminal |[http://tinkerpop.apache.org/docs/current/reference/#terminal-steps terminal-steps terminal-steps] | |will return the next result.next(n) will return the next n results in a list |-|- |option |modulator |[http://tinkerpop.apache.org/docs/current/reference/#option-step option-step option-step] | |An option to a branch() or choose() |-|- |or |filter |[http://tinkerpop.apache.org/docs/current/reference/#or-step or-step or-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#or-org.apache.tinkerpop.gremlin.process.traversal.Traversal...- or-org.apache.tinkerpop.gremlin.process.traversal.Traversal...- or] |ensures that at least one of the provided traversals yield a result. |-|- |order |map |[http://tinkerpop.apache.org/docs/current/reference/#order-step order-step order-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#order--,order-org.apache.tinkerpop.gremlin.process.traversal.Scope- order--,order-org.apache.tinkerpop.gremlin.process.traversal.Scope- order] |orders the traversal elements |-|- |out |flatMap | | |maps the current elements to the vertices at the end of the outgoing edges. |-|- |outE |flatMap | | |maps the current elements to the the outgoing edges. |-|- |outV |flatMap | | |The outV step maps the current edges to the outgoing Vertices. |-|- |path |map |[http://tinkerpop.apache.org/docs/current/reference/#path-step path-step path-step] | | |-|- |promise |terminal |[http://tinkerpop.apache.org/docs/current/reference/#terminal-steps terminal-steps terminal-steps] | |can only be used with remote traversals to Gremlin Server or RGPs. It starts a promise to execute a function on the current Traversal that will be completed in the future. |-|- |property |sideEffect |[http://tinkerpop.apache.org/docs/current/reference/#addproperty-step addproperty-step addproperty-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#property-java.lang.Object-java.lang.Object-java.lang.Object...- property-java.lang.Object-java.lang.Object-java.lang.Object...- property] |is used to add properties to the elements of the graph |-|- |range |filter |[http://tinkerpop.apache.org/docs/current/reference/#range-step range-step range-step] | | |-|- |repeat |branch |[http://tinkerpop.apache.org/docs/current/reference/#repeat-step repeat-step repeat-step] |[http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#repeat-org.apache.tinkerpop.gremlin.process.traversal.Traversal-,repeat-java.lang.String-org.apache.tinkerpop.gremlin.process.traversal.Traversal- repeat-org.apache.tinkerpop.gremlin.process.traversal.Traversal-,repeat-java.lang.String-org.apache.tinkerpop.gremlin.process.traversal.Traversal- repeat] |is used for looping over a traversal given some break predicate |-|- |select |map |[http://tinkerpop.apache.org/docs/current/reference/#select-step select-step select-step] | | |-|- |sideEffect |general |[http://tinkerpop.apache.org/docs/current/reference/#general-steps general-steps general-steps] | |performs some operation on the traverser and passes it to the next step. |-... further results


Stephierarchy

All steps are based on five general steps. Click on any of the steps below to see the explanation for the step

terminal Steps

hasNext Step

The hasNext step determines whether there are available results

  @Test
  public void testHasNext() {
    assertTrue(g().V(1).hasNext());
    assertFalse(g().V(7).hasNext());
  }

next Step

The next step will return the next result.next(n) will return the next n results in a list

. @Test
  public void testNext() {
    assertEquals("v[1]",g().V().next().toString());
    assertEquals("v[1]",g().V(1).next().toString());
    assertEquals("[v[1], v[2]]",g().V(1,2,3).next(2).toString());
  }

tryNext Step

The tryNext step will return an Optional and thus, is a composite of hasNext()/next()

  @Test
  public void testTryNext() {
    assertTrue(g().V(1).tryNext().isPresent());
    assertFalse(g().V(7).tryNext().isPresent());
  }

toList Step

The toList step will return all results in a list

  @Test
  public void testToList() {
    List<Vertex> vlist = g().V().toList();
    assertEquals("[v[1], v[2], v[3], v[4], v[5], v[6]]", vlist.toString());
    List<Edge> elist = g().E(7,8,9).toList();
    assertEquals(
        "[e[7][1-knows->2], e[8][1-knows->4], e[9][1-created->3]]",
        elist.toString());
  }

toSet Step

The toSet step will return all results in a set and thus, duplicates removed

  @Test
  public void testToSet() {
    Set<Vertex> vset = g().V(1,2,2,3,4).toSet();
    assertEquals("[v[1], v[2], v[3], v[4]]", vset.toString());
    Set<Edge> set = g().E(7,8,9,7,8,9).toSet();
    assertEquals(
        "[e[7][1-knows->2], e[8][1-knows->4], e[9][1-created->3]]",
        set.toString());
  }

toBulkSet Step

The toBulkSet step will return all results in a weighted set and thus, duplicates preserved via weighting

  @Test
  public void testToBulkSet() {
    BulkSet<Vertex> vset = g().V(1,2,2,3,4).toBulkSet();
    assertEquals(2,vset.asBulk().get(g().V(2).next()).longValue());
  }

fill Step

The fill step fill(collection) will put all results in the provided collection and return the collection when complete.

  @Test
  public void testFill() {
    List<Vertex> vlist=new LinkedList<Vertex>();
    List<Vertex> rvlist = g().V().fill(vlist);
    assertEquals(vlist,rvlist);
    assertEquals("[v[1], v[2], v[3], v[4], v[5], v[6]]", vlist.toString());
  }

iterate Step

The iterate step Iterates the traversal presumably for the generation of side-effects. See https://stackoverflow.com/questions/47403296/iterate-step-is-used-in-the-end-of-the-command-when-creating-nodes-and-edges-t

 @Test
  public void testIterate() throws IOException {
    // read and write without iterate doesn't have an effect
    File kryoFile=File.createTempFile("modern", ".kryo");
    g().io(kryoFile.getPath()).write();
    GraphTraversalSource newg = TinkerGraph.open().traversal();
    newg.io(kryoFile.getPath()).read();
    assertEquals(0,newg.V().count().next().longValue());
    
    // read and write with iterate does really write and read
    g().io(kryoFile.getPath()).write().iterate();
    newg = TinkerGraph.open().traversal();
    newg.io(kryoFile.getPath()).read().iterate();
    assertEquals(6,newg.V().count().next().longValue());
  }

promise Step

The promise step can only be used with remote traversals to Gremlin Server or RGPs. It starts a promise to execute a function on the current Traversal that will be completed in the future.

  @Test
  public void testPromise() {
    try {
      CompletableFuture<Object> cf = g().V().promise(t -> t.next());
      cf.join();
      assertTrue(cf.isDone());
    } catch (Exception e) {
      assertEquals(
          "Only traversals created using withRemote() can be used in an async way",
          e.getMessage());
    }
  }

explain Step

The explain step will return a TraversalExplanation. A traversal explanation details how the traversal (prior to explain()) will be compiled given the registered traversal strategies. A TraversalExplanation has a toString() representation with 3-columns. The first column is the traversal strategy being applied. The second column is the traversal strategy category: [D]ecoration, [O]ptimization, [P]rovider optimization, [F]inalization, and [V]erification. Finally, the third column is the state of the traversal post strategy application. The final traversal is the resultant execution plan.

@Test
  public void testExplain() {
    TraversalExplanation te = g().V().explain();
    assertEquals("Traversal Explanation\n"
        + "===============================================================\n"
        + "Original Traversal                 [GraphStep(vertex,[])]\n" + "\n"
        + "ConnectiveStrategy           [D]   [GraphStep(vertex,[])]\n"
        + "CountStrategy                [O]   [GraphStep(vertex,[])]\n"
        + "IncidentToAdjacentStrategy   [O]   [GraphStep(vertex,[])]\n"
        + "RepeatUnrollStrategy         [O]   [GraphStep(vertex,[])]\n"
        + "MatchPredicateStrategy       [O]   [GraphStep(vertex,[])]\n"
        + "PathRetractionStrategy       [O]   [GraphStep(vertex,[])]\n"
        + "FilterRankingStrategy        [O]   [GraphStep(vertex,[])]\n"
        + "InlineFilterStrategy         [O]   [GraphStep(vertex,[])]\n"
        + "AdjacentToIncidentStrategy   [O]   [GraphStep(vertex,[])]\n"
        + "LazyBarrierStrategy          [O]   [GraphStep(vertex,[])]\n"
        + "TinkerGraphCountStrategy     [P]   [GraphStep(vertex,[])]\n"
        + "TinkerGraphStepStrategy      [P]   [TinkerGraphStep(vertex,[])]\n"
        + "ProfileStrategy              [F]   [TinkerGraphStep(vertex,[])]\n"
        + "StandardVerificationStrategy [V]   [TinkerGraphStep(vertex,[])]\n"
        + "\n"
        + "Final Traversal                    [TinkerGraphStep(vertex,[])]",
        te.toString());
  }

filter Steps

and Step

The and step (javadoc)ensures that all provided traversals yield a result

  @Test
  public void testAnd() {
    assertEquals("[marko]",g().V().and(
        outE("knows"),
        values("age").is(lt(30))).
          values("name").toList().toString());
  }

coin Step

The coin step (javadoc)randomly filters out traversers with the given probability

@Test
  public void testCoin() {
    // 0% chance
    assertEquals("[]", g().V().coin(0.0).toList().toString());
    // 100% chance
    assertEquals("[v[1], v[2], v[3], v[4], v[5], v[6]]",
        g().V().coin(1.0).toList().toString());
    // 50 % chance
    int tosses = 1000;
    double sixsigma=0.33; // 1 out of a million chance that the average will deviate more than this
    int sum = 0;
    for (int i = 1; i <= tosses; i++)
      sum += g().V().coin(0.5).toList().size();
    double avg = sum * 1.0 / tosses;
    assertTrue(avg<3.0+sixsigma);
    assertTrue(avg>3.0-sixsigma);
  }

has Step

The has step (javadoc)filters vertices, edges, and vertex properties based on their properties. This step has quite a few variations.

  @Test
  public void testHas() {
    assertEquals(6, g().V().has("name").count().next().longValue());
    assertEquals("[29, 27]",
        (g().V().has("age", inside(20, 30)).values("age").toList().toString()));
    assertEquals("[32, 35]", (g().V().has("age", outside(20, 30)).values("age")
        .toList().toString()));
    assertEquals("[{name=[marko], age=[29]}, {name=[josh], age=[32]}]", (g().V()
        .has("name", within("josh", "marko")).valueMap().toList().toString()));
    assertEquals("[lop, ripple]",g().V().hasNot("age").values("name").toList().toString());
  }

is Step

The is step (javadoc)filters elements that fullfill the given predicate. Variant: Filters elements that are equal to the given Object.

  @Test
  public void testIs() {
    assertEquals("[32]", g().V().values("age").is(32).toList().toString());
    assertEquals("[29, 27]",
        g().V().values("age").is(lte(30)).toList().toString());
    assertEquals("[32, 35]",
        g().V().values("age").is(inside(30, 40)).toList().toString());
    assertEquals("[ripple]", g().V().where(in("created").count().is(1))
        .values("name").toList().toString());
    assertEquals("[lop]", g().V().where(in("created").count().is(gte(2)))
        .values("name").toList().toString());
    assertEquals("[lop, ripple]",
        g().V().where(in("created").values("age").mean().is(inside(30d, 35d)))
            .values("name").toList().toString());
  }

or Step

The or step (javadoc)ensures that at least one of the provided traversals yield a result.

 @Test
  public void testOr() {
    assertEquals("[marko, lop, josh, peter]",
        g().V().or(outE("created"), inE("created").count().is(gt(1)))
            .values("name").toList().toString());
    assertEquals("[vadas, peter]",
        g().V().or(values("age").is(gt(33)), values("age").is(lt(29)))
            .values("name").toList().toString());
  }

where Step

The where step filters the current object based on either the object itself (Scope.local) or the path history of the object (Scope.global) (filter). This step is typically used in conjunction with either #match Step or select()-step, but can be used in isolation.

  @Test
  public void testWhere() {
    assertEquals("[v[4], v[6]]", g().V(1).as("a").out("created").in("created")
        .where(neq("a")).toList().toString());
    String names[] = { "josh", "peter" };
    assertEquals("[josh, peter]",
        g().withSideEffect("a", Arrays.asList(names)).V(1).out("created")
            .in("created").values("name").where(within("a")).toList()
            .toString());
    assertEquals("[josh]",
        g().V(1).out("created").in("created")
            .where(out("created").count().is(gt(1))).values("name").toList()
            .toString());
  }

Step Modulators

as Step

The as step (javadoc)is not a real step, but a "step modulator" similar to by() and option(). With as(), it is possible to provide a label to the step that can later be accessed by steps and data structures that make use of such labels — e.g., select(), match(), and path

  @Test
  public void testAs() {
    assertEquals(
        "[{a=v[1], b=v[3]}, {a=v[4], b=v[5]}, {a=v[4], b=v[3]}, {a=v[6], b=v[3]}]",
        g().V().as("a").out("created").as("b").select("a", "b").toList()
            .toString());
    assertEquals(
        "[{a=marko, b=lop}, {a=josh, b=ripple}, {a=josh, b=lop}, {a=peter, b=lop}]",
        g().V().as("a").out("created").as("b").select("a", "b").by("name")
            .toList().toString());
  }

by Step

The by step (javadoc)is not an actual step, but instead is a "step-modulator" similar to as() and option(). If a step is able to accept traversals, functions, comparators, etc. then by() is the means by which they are added. The general pattern is step().by()…​by(). Some steps can only accept one by() while others can take an arbitrary amount.

  @Test
  public void testBy() {
    assertEquals("[{1=[v[2], v[5], v[6]], 3=[v[1], v[3], v[4]]}]",
        g().V().group().by(bothE().count()).toList().toString());
    assertEquals("[{1=[vadas, ripple, peter], 3=[marko, lop, josh]}]",
        g().V().group().by(bothE().count()).by("name").toList().toString());
    assertEquals("[{1=3, 3=3}]",
        g().V().group().by(bothE().count()).by(count()).toList().toString());
  }

option Step

The option step

map Steps

id Step

The id step maps the traversal to the ids of the current elements.

  @Test
  public void testId() {
    List<Object> vids = g().V().id().toList();
    assertEquals(6,vids.size());
    assertEquals("[1, 2, 3, 4, 5, 6]",vids.toString());
    List<Object> eids = g().E().id().toList();
    assertEquals(6,eids.size());
    assertEquals("[7, 8, 9, 10, 11, 12]",eids.toString());
  }


label Step

The label step maps the traversal to the labels of the current elements.

  @Test
  public void testLabel() {
    List<String> vlabels = g().V().label().toList();
    assertEquals(6,vlabels.size());
    assertEquals("[person, person, software, person, software, person]",vlabels.toString());
    List<String> elabels = g().E().label().toList();
    assertEquals(6,elabels.size());
    assertEquals("[knows, knows, created, created, created, created]",elabels.toString());
  }

match Step

The match step see https://stackoverflow.com/questions/55609832/is-threre-a-document-about-how-gremlin-match-works


path Step

The path step


select Step

The select step


order Step

The order step

reducing barrier Steps

count Step

The count step (javadoc)counts the total number of represented traversers in the streams (i.e. the bulk count).

@Test
  public void testCount() {
    assertEquals(6,g().V().count().next().longValue());
    assertEquals(4,g().V().hasLabel("person").count().next().intValue());
    assertEquals(2,g().V().hasLabel("software").count().next().intValue());
    assertEquals(4,g().E().hasLabel("created").count().next().intValue());
    assertEquals(2,g().E().hasLabel("knows").count().next().intValue());
  }

min Step

The min step operates on a stream of comparable objects and determines which is the first object according to its natural order in the stream.

@Test
  public void testMin() {
    assertEquals(27,g().V().values("age").min().next());
    assertEquals(0.2,g().E().values("weight").min().next());
    assertEquals("josh",g().V().values("name").min().next());
  }

max Step

The max step operates on a stream of comparable objects and determines which is the last object according to its natural order in the stream.

@Test
  public void testMax() {
    assertEquals(35,g().V().values("age").max().next());
    assertEquals(1.0,g().E().values("weight").max().next());
    assertEquals("vadas",g().V().values("name").max().next());
  }

mean Step

The mean step operates on a stream of numbers and determines the average of those numbers.

@Test
  public void testMean() {
    assertEquals(30.75, g().V().values("age").mean().next());
    assertEquals(0.583, g().E().values("weight").mean().next().doubleValue(),
        0.001);
    try {
      assertEquals("josh", g().V().values("name").mean().next());
    } catch (Exception e) {
      assertEquals("java.lang.String cannot be cast to java.lang.Number",e.getMessage());
    }
  }

sum Step

The sum step operates on a stream of numbers and sums the numbers together to yield a result

@Test
  public void testSum() {
    assertEquals(123, g().V().values("age").sum().next().intValue());
    assertEquals(3.5, g().E().values("weight").sum().next().doubleValue(),0.01);
  }

fold Step

The fold step There are situations when the traversal stream needs a "barrier" to aggregate all the objects and emit a computation that is a function of the aggregate. The fold()-step (map) is one particular instance of this. Please see unfold()-step for the inverse functionality.

@Test
  public void testFold() {
    List<Object> knowsList1 = g().V(1).out("knows").values("name").fold().next();
    assertEquals("[vadas, josh]",knowsList1.toString());
  }

flatMap Steps

in Step

The in step maps the current elements to the vertices at the end of the ingoing edges.

  @Test
  public void testIn() {
    assertEquals("[v[1], v[1], v[4], v[6], v[1], v[4]]",
        g().V().in().toList().toString());
    assertEquals("[v[1], v[4], v[6], v[4]]",
        g().V().in("created").toList().toString());
    assertEquals("[v[1], v[1]]", g().V().in("knows").toList().toString());
    assertEquals("[v[1], v[1], v[4], v[6], v[1], v[4]]",
        g().V().in("created","knows").toList().toString());
  }

out Step

The out step maps the current elements to the vertices at the end of the outgoing edges.

  @Test
  public void testOut() {
    assertEquals("[v[3], v[2], v[4], v[5], v[3], v[3]]",
        g().V().out().toList().toString());
    assertEquals("[v[3], v[5], v[3], v[3]]",
        g().V().out("created").toList().toString());
    assertEquals("[v[2], v[4]]", g().V().out("knows").toList().toString());
    assertEquals("[v[3], v[2], v[4], v[5], v[3], v[3]]",
        g().V().out("created","knows").toList().toString());
  }

both Step

The both step maps the current elements to the vertices at the boths ends of the edges.

  @Test
  public void testBoth() {
    assertEquals("[v[5], v[3], v[1]]",
      g().V(4).both().toList().toString());
    assertEquals("[v[5], v[3]]",
        g().V(4).both("created").toList().toString());
    assertEquals("[v[1]]", g().V(4).both("knows").toList().toString());
    assertEquals("[v[5], v[3], v[1]]",
        g().V(4).both("created","knows").toList().toString());
  }

inE Step

The inE step maps the current elements to the the ingoing edges.

@Test
  public void testInE() {
    assertEquals(
        "[e[7][1-knows->2], e[9][1-created->3], e[11][4-created->3], e[12][6-created->3], e[8][1-knows->4], e[10][4-created->5]]",
        g().V().inE().toList().toString());
    assertEquals(
        "[e[9][1-created->3], e[11][4-created->3], e[12][6-created->3], e[10][4-created->5]]",
        g().V().inE("created").toList().toString());
    assertEquals("[e[7][1-knows->2], e[8][1-knows->4]]",
        g().V().inE("knows").toList().toString());
    assertEquals(
        "[e[7][1-knows->2], e[9][1-created->3], e[11][4-created->3], e[12][6-created->3], e[8][1-knows->4], e[10][4-created->5]]",
        g().V().inE("created", "knows").toList().toString());
  }

outE Step

The outE step maps the current elements to the the outgoing edges.

  @Test
  public void testOutE() {
    assertEquals(
        "[e[9][1-created->3], e[7][1-knows->2], e[8][1-knows->4]]",
        g().V(1).outE().toList().toString());
    assertEquals(
        "[e[9][1-created->3]]",
        g().V(1).outE("created").toList().toString());
    assertEquals("[e[7][1-knows->2], e[8][1-knows->4]]",
        g().V(1).outE("knows").toList().toString());
    assertEquals(
        "[e[9][1-created->3], e[7][1-knows->2], e[8][1-knows->4]]",
        g().V(1).outE("created", "knows").toList().toString());
  }

bothE Step

The bothE step maps the current elements to both the in and outgoing edges.

  @Test
  public void testBothE() {
    assertEquals("[e[10][4-created->5], e[11][4-created->3], e[8][1-knows->4]]",
        g().V(4).bothE().toList().toString());
    assertEquals("[e[10][4-created->5], e[11][4-created->3]]",
        g().V(4).bothE("created").toList().toString());
    assertEquals("[e[8][1-knows->4]]",
        g().V(4).bothE("knows").toList().toString());
    assertEquals("[e[10][4-created->5], e[11][4-created->3], e[8][1-knows->4]]",
        g().V(4).bothE("created", "knows").toList().toString());
  }

inV Step

The inV step maps the current edges to the the ingoing Vertices.

  @Test
  public void testInV() {
    assertEquals("[v[2], v[4], v[3], v[5], v[3], v[3]]",
        g().E().inV().toList().toString());
    assertEquals("[v[3]]", g().E(9).inV().toList().toString());
  }

outV Step

The outV step The outV step maps the current edges to the outgoing Vertices.

  @Test
  public void testOutV() {
    assertEquals("[v[1], v[1], v[1], v[4], v[4], v[6]]",
        g().E().outV().toList().toString());
    assertEquals("[v[1]]", g().E(9).outV().toList().toString());
  }

bothV Step

The bothV step maps the current edges to both the ingoing and outgoing Vertices.

  @Test
  public void testBothV() {
    assertEquals("[v[4], v[3]]",
        g().E(11).bothV().toList().toString());
    assertEquals("[v[1], v[3]]", g().E(9).bothV().toList().toString());
  }

coalesce Step

The coalesce step The coalesce()-step evaluates the provided traversals in order and returns the first traversal that emits at least one element.


Side Effect Steps

addE Step

The addE step (javadoc)is used to add edges to the graph

  @Test
  public void testAddE() {
    Vertex marko = g().V().has("name","marko").next();
    Vertex peter = g().V().has("name","peter").next();   
    assertEquals("e[13][1-knows->6]",g().V(marko).addE("knows").to(peter).next().toString());
    assertEquals("e[13][1-knows->6]",g().addE("knows").from(marko).to(peter).next().toString());
  }

addV Step

The addV step (javadoc)is used to add vertices to the graph

  @Test
  public void testAddV() {
    assertEquals("[marko, vadas, lop, josh, ripple, peter, stephen]",
        g().addV("person").property("name", "stephen").V().values("name").toList()
            .toString());
  }

property Step

The property step (javadoc)is used to add properties to the elements of the graph

  @Test
  public void testProperty() {
    assertEquals("[v[3]]",g().V().has("name","lop").property("version","1.0").V().has("version").toList().toString());
  }

aggregate Step

The aggregate step (javadoc)is used to aggregate all the objects at a particular point of traversal into a Collection

  @Test
  public void testAggregate() {
    assertEquals("[ripple]",g().V(1).out("created").aggregate("x").in("created").out("created").
                where(without("x")).values("name").toList().toString());
    assertEquals("[{vadas=1, josh=1}]",g().V().out("knows").aggregate("x").by("name").cap("x").toList().toString());
  }

General Steps

filter Step

Continues processing based on the given filter condition.

  @Test
  public void testFilter() {
    assertEquals(3,g().V().filter(out()).count().next().longValue());
    assertEquals(4,g().V().filter(in()).count().next().longValue());
    assertEquals(5,g().E().filter(values("weight").
      is(P.gte(0.4))).count().next().longValue());
  }

There are 3 vertices having outgoing edges and 4 vertices having incoming edges in the modern example graph. There are 4 edges having a weight>=0.4;

map Step

A map step transforms the current step element to a new element (which may be empty). see also https://stackoverflow.com/questions/51015636/in-gremlin-how-does-map-really-work

 @Test
  public void testMap() {
    assertEquals(6,g().V().map(values("name")).count().next().longValue());
    assertEquals(4,g().V().map(hasLabel("person")).count().next().longValue());
    assertEquals(2,g().V().map(has("lang","java")).count().next().longValue());
    List<Edge> outEdges = g().V().map(outE()).toList();
    assertEquals(3,outEdges.size());
    List<Object> edges = g().E().map(has("weight",0.4)).toList();
    assertEquals(2,edges.size());
    for (Object edge:edges) {
      assertTrue(edge instanceof Edge);
    }
  }

There are 6 vertices having a name property. There are 4 vertices with a "person" label. There are 2 vertices with the lang property having the value "java".There are 3 vertices having out edges. The toList() call returns a list of Edges. There are 2 edges having a weight of 0.4. The map step toList() returns a list of the edges for this last example (which are returned as generic objects).

flatMap Step

A flatMap step transforms the current step in a one to many fashion.

 @Test
  public void testflatMap() {
    assertEquals(6,g().V().flatMap(values("name")).count().next().longValue());
    assertEquals(4,g().V().flatMap(hasLabel("person")).count().next().longValue());
    assertEquals(2,g().V().flatMap(has("lang","java")).count().next().longValue());
    List<Edge> outEdges = g().V().flatMap(outE()).toList();
    assertEquals(6,outEdges.size());
    List<Object> edges = g().E().flatMap(has("weight",0.4)).toList();
    assertEquals(2,edges.size());
    for (Object edge:edges) {
      assertTrue(edge instanceof Edge);
    }
  }

Note the difference to the testMap step. Only the outE() parameter behaves different. In the map() case only the first Edge is considered - in the flatMap case all edges are considered.

sideEffect Step

A sideEffect steps performs some operation on the traverser and passes it to the next step.


  @Test
  public void testSideEffect() {
    assertEquals(6,g().V().sideEffect(addE("sideedge")).outE().
      hasLabel("sideedge").count().next().longValue());
  }

The sideffect in this example JUnit test case adds edges "on the fly".

branch Step

Split the traverser

  @Test
  public void testBranch() {
   
  }

What links here

Links

Stackoverflow Questions

Recipes

Practical Gremlin: An Apache TinkerPop Tutorial by Kelvin Lawrence

load PDF

Traversing Graphs with Gremlin