Problem using defineStep with Gremlin (2.5.0)

108 views
Skip to first unread message

Craig Trader

unread,
Oct 9, 2014, 6:47:09 PM10/9/14
to gremli...@googlegroups.com
I'm using Gremlin 2.5.0 with OrientDB 1.7.8.  I have a fairly complex graph database (750,000+ vertexes, using classes, with indexed keys/class).  A typical Gremlin query might look like:

g.getVertices('foo.key','foo1')._().inE('links').outV().inE('connects').outV()

This query starts with a single 'foo' vertex, traces through one or more 'links' edges to their connected 'bar' vertexes, and then repeats that for 'connects' edges to get to 'baz' vertexes.  I want the list of 'baz' vertexes. When I run this query from the Gremlin shell, it works great, returning v(baz)[#34:233]. Alas, I want to run this query (and many like it) from a program, and that's where my problems start.

From Java I can execute this code:

GremlinPipeline<Iterable<Vertex>, Vertex> pipe = new GremlinPipeline<>();
pipe.start(g.getVertices("foo.key", "foo1")).inE("links").outV().inE("connects").outV();
for (Vertex v : pipe) { LOGGER.info("result = {}", v); }

From Groovy I can execute this code:

new GremlinGroovyPipeline( g.getVertices("foo.key", "foo1") ).inE('links').outV().inE('connects').outV().each( { println it } )

This works fine for me, but I have been tasked to take advantage of Groovy's DSL capabilities and clean this up so that mortals can easily make sense of it. From the Gremlin shell, I can use Gremlin.defineStep to create some custom steps, as follows:

Gremlin.defineStep( 'bars', [Vertex, Pipe], { _().has('keytype','foo').inE('links').outV().has('keytype','bar') } )
Gremlin.defineStep( 'bazs', [Vertex, Pipe], { _().has('keytype','bar').inE('connects').outV().has('keytype','baz') } )

Which allows me to use the following query:

g.getVertices('foo.key','foo1')._().bars.bazs

Unfortunately, when I try to define those steps within a Groovy class for use in my application:

Gremlin.defineStep( 'bars', [Vertex, Pipe], { _().has('keytype','foo').inE('links').outV().has('keytype','bar') } )
Gremlin.defineStep( 'bazs', [Vertex, Pipe], { _().has('keytype','bar').inE('connects').outV().has('keytype','baz') } )
new GremlinGroovyPipeline( g.getVertices("foo.key", "foo1") ).bars.bazs.each( { println it } )

I get the following exception (at runtime):

Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: com.example.test.GroovyTest$_mfv2_closure1._() is applicable for argument types: () values: []

Possible solutions: is(java.lang.Object), is(java.lang.Object), any(), any(), any(groovy.lang.Closure), use([Ljava.lang.Object;)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:379)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:723)
at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java:44)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:72)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:137)
at com.verisign.test.GroovyTest$_mfv2_closure1.doCall(GroovyTest.groovy:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at com.verisign.test.GroovyTest$_mfv2_closure1.doCall(GroovyTest.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at com.tinkerpop.gremlin.groovy.Gremlin$_defineStep_closure2_closure5.doCall(Gremlin.groovy:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:80)
at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:816)
at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1128)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1081)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:781)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:772)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:164)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:185)
at com.tinkerpop.gremlin.groovy.loaders.PipeLoader$_load_closure1.doCall(PipeLoader.groovy:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:80)
at groovy.lang.MetaClassImpl.invokeMissingProperty(MetaClassImpl.java:771)
at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1621)
at groovy.lang.ExpandoMetaClass.getProperty(ExpandoMetaClass.java:1136)
at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3343)
at groovy.lang.ExpandoMetaClass.getProperty(ExpandoMetaClass.java:1148)
at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:161)
at org.codehaus.groovy.runtime.callsite.PojoMetaClassGetPropertySite.getProperty(PojoMetaClassGetPropertySite.java:33)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
at com.example.test.GroovyTest.test1(GroovyTest.groovy:29)

A suggestion on what I'm doing wrong would be helpful; my thanks in advance for what assistance you can provide.
 

Stephen Mallette

unread,
Oct 10, 2014, 5:35:26 AM10/10/14
to gremli...@googlegroups.com
Are you statically loading Gremlin in you groovy application?

static { Gremlin.load() }


--
You received this message because you are subscribed to the Google Groups "Gremlin-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/749dff36-a579-409b-9b89-9c498eedced4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Craig Trader

unread,
Oct 10, 2014, 6:56:41 AM10/10/14
to gremli...@googlegroups.com
Yes.

Craig Trader

unread,
Oct 10, 2014, 12:53:07 PM10/10/14
to gremli...@googlegroups.com
Ok.  I seem to have solved the problem, but the solution seems insane.

I had been testing with static methods. In order to abstract as much of the problem as possible, I pulled all of my code into a single Groovy class (using a single static main method) and was able to reproduce both the query working correctly standalone, and yet failing when I used the defined steps. As a lark, I changed it to run as a regular method, called from the static main method ... and all of a sudden the defined steps work as expected.

So the question becomes, why does Gremlin.defineStep work from an instance method, but not a static method?

- Craig -

Stephen Mallette

unread,
Oct 11, 2014, 9:52:57 AM10/11/14
to gremli...@googlegroups.com
I've been bitten by that before and never remember it as the solution to the problem.  That said, I'm also semi-convinced it doesn't always have to be that way either (which is why I've not documented it one way or another).  I don't know exactly what causes things to not register themselves properly from the static perspective all the time.

W. Craig Trader

unread,
Oct 11, 2014, 10:35:45 AM10/11/14
to gremli...@googlegroups.com

My final solution was to create a class to hold my DSL bits. The class has a static "load" method which checks a static "loaded" flag. If it's already been loaded, it does nothing, otherwise it calls Gremlin.load() and then initializes an instance of the DSL class, which does all of the defineStep() calls, along with my other metaClass work.

I can call DSL.load() from a static method, go figure.

I think that since the defineStep calls shouldn't be repeated (and are somewhat slow due to all of the initialization overhead) that this pattern should be described in the wiki page about custom steps.

- Craig -

Craig Trader

unread,
Oct 13, 2014, 1:58:55 PM10/13/14
to gremli...@googlegroups.com
DSL.groovy:

package com.example.util

import com.tinkerpop.blueprints.Graph
import com.tinkerpop.blueprints.Vertex
import com.tinkerpop.gremlin.groovy.Gremlin
import com.tinkerpop.pipes.Pipe

class DSL {
private static boolean loaded = false

/**
* This loads and initializes Gremlin, and defines the DSL extensions for Groovy and Gremlin
*/
public static void load() {
if (!loaded) {
Gremlin.load()
DSL dsl = new DSL()
loaded = true
}
}

private DSL() {

// Extend the Graph class
Graph.metaClass.start_vertex = { String classname, String key ->
delegate.getVertices( classname+".key", key )._()
}

// Add custom Gremlin steps

Gremlin.defineStep( 'bars', [Vertex, Pipe ]) { 
_().has('keytype','foo').inE('links').outV().has('keytype','bar')
}

Gremlin.defineStep( 'bazs', [Vertex, Pipe ]) {
_().has('keytype','bar').inE('links').outV().has('keytype','baz') 
}
}
}
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-users+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Gremlin-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages