Hello,
I’m really proud of the new math()-step. It is a really powerful and elegant solution to arbitrary calculations of traverser scopes. For shits and giggles, I want to take this email to explain “scoping” in Gremlin and to show off math().
Scoping is a big concept in Gremlin. There is a Scoping interface that scope-based steps implement.
There are four types of scopes:
1. Current scope — the current data referenced by the traverser (“path head”).
2. Path scope — a particular piece of data in the path of the traverser (“path history”).
3. Side-effect scope — a particular piece of data in the global traversal blackboard.
4. Map scope — a particular piece of data in the current scope map (“map value by key”).
I will demonstrate each scope using the new math()-step which, in fact, implements Scoping.
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
1. Current Scope
The current scope refers to the current object referenced by the traverser. That is, the “traverser.get()” object. Another way to think about the current scope is to think in terms of the path of the traverser where the current scope is the head of the path. With the math()-step, the variable _ refers to the current scope.
gremlin> g.V().values("age").math("sin _")
2. Path Scope
The path scope refers to data previously seen by the traverser. That is, data in the traverser’s path history. Paths can be accessed by path(), however, individual parts of the path can be labeled using as() and accessed later via the path label name. Thus, in the traversal below, “a” and “b” refer to objects previously traversed by the traverser.
gremlin> g.V().as("a").out("knows").as("b”).
math("a / b").by("age")
3. Side-Effect Scope
The side-effect scope refers objects in the global side-effects of the traversal. Side-effects are not local to the traverser, but instead, global to the traversal. In the traversal below you can see how “x” is being referenced in the math()-step and thus, the side-effect data is being used.
gremlin> g.withSideEffect("x",100).V().values("age").math("_ / x")
4. Map Scope
Map scope refers to objects within the current map object. Thus, its like current scope, but a bit “deeper.” In the traversal below the project()-step generates a map with keys “a” and “b”. The subsequent math()-step is then able to access the “a” and “b” values in the respective map and use them for the division operation.
gremlin> g.V().hasLabel("person”).
project("a","b”).
by("age”).
by(bothE().count()).
math("a / b")
Scoping is all about variable data access and forms the fundamental interface for access to the memory structures of Gremlin. In essence, it is through scoping that Gremlin moves beyond being a finite state machine to a push down automata and from their enjoys all the expressivity that that entails.
I hope that was useful.
Take care,
Marko.