Hello,

ScriptEngine’s prefer to have compile scripts with bindings as a compiled 
script will execute much faster than one that needs to be compiled. Thus, for a 
traversal that will be run over and over again, but with for instance different 
g.V(id) sources, its all about using ScriptEngine bindings. How do we support 
bindings in a language agnostic way? 

The big problem is Java. The GraphTraversal API is strongly typed and thus, we 
can’t simply do stuff like g.V(bind(“id”,2)). Or can we?

b = new Bindings();
g = graph.traversal().withBindings(b);
g.V(b.of(“id”,2)).out(“created”).values(“name”)

What is this all about?

When you do b.of(“id”,2), it returns 2 (Java API is happy). However, the 
underlying Bytecode will know when a new argument has been passed to it. It 
will ask Bindings, "was a binding for 2 just added?" If so, then the Bytecode 
rewrites itself such that the argument is binding(“id”,2).

Then, when the traversal is sent to GremlinServer to be evaluated (lets say via 
Gremlin-Groovy), the Bytecode translator will make the Groovy String script 
look as:

g.V(id).out(“created”).values(“name”)

And it will have JSR223 ScriptEngine bindings of {id:2}.

        
https://github.com/apache/tinkerpop/blob/TINKERPOP-1278/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/java/translator/GroovyTranslator.java
 
<https://github.com/apache/tinkerpop/blob/TINKERPOP-1278/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/java/translator/GroovyTranslator.java>

Thus, TinkerPop Bindings become a first class citizen in Gremlin. Next, what 
about when Gremlin-Java is translating Bytecode. Well, Java doesn’t care about 
script compilation speed as its Bytecode translator doesn’t generate a String, 
but a Traversal via reflection. 

        
https://github.com/apache/tinkerpop/blob/TINKERPOP-1278/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/JavaTranslator.java
 
<https://github.com/apache/tinkerpop/blob/TINKERPOP-1278/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/JavaTranslator.java>

If JavaTranslator sees a binding in the Bytecode is ignores the binding key, 
and only uses its value:

g.V(2).out(“created”).values(“name”)

So this can get awkward for users. However, we can make bindings reusable.

b = new Bindings();
g = graph.traversal().withBindings(b);
g.V(b.of(“id”,2)).out(“created”).values(“name”)
b.clear()
g.V().out(b.of(“a”,”knows”))
b.clear()

In fact, it would be possible to automatically reset the bindings every time a 
traversal is compiled. Thus,

b = new Bindings();
g = graph.traversal().withBindings(b);
g.V(b.of(“id”,2)).out(“created”).values(“name”)
g.V().out(b.of(“a”,”knows”))
 
Now, you may say — “well, aren’t traversal sources suppose to be thread safe.” 
To that I say: “yes and if you do it like this, you can only execute one 
traversal at a time.” If you want thread safety:

g = graph.traversal();
b = new Bindings();
g.withBindings(b).V(b.of(“id”,2)).out(“created”).values(“name”)
g.withBindings(b).V().out(b.of(“a”,”knows”))

For most people, they will have a RemoteGraph traversal source and not worry 
about thread safety here. On GremlinServer, thread safety isn’t an issue as 
withBindings() is a TraversalSource step and thus, part of the Bytecode 
reconstructed at compile time.

Anywho, that is the best I could come up with that will work for Java, Groovy, 
and Python. Unfortunately Java (and Groovy) are statically typed so we have to 
work around this.

Thoughts?,
Marko.

http://markorodriguez.com



Reply via email to