Technology•July 25, 2013
Developing a Domain Specific Language in Gremlin

g.V.has('type','post')
g.V.has('type','post').out('child').loop(1){it.loops<25}{true}
m=[:]
g.V.has('type','post').out('child').loop(1){it.loops<25}{true}
.path.groupBy(m){it[0].userName}{it}{it.collectMany{it}.unique()}.iterate()
gremlin> m
==>marko=[v[184476380], v[282106584], v[184550536], v[189966816]]
==>josh=[v[173318448], v[188571048]]
==>daniel=[v[186130596], v[308964172]]
...
==>stephen=[v[176281532], v[182440524], v[188572948], v[282049412]]
class S {
public static final String EDGE_CHILD = "child"
public static final String PROPERTY_POST_ID = "postId"
public static final String PROPERTY_TYPE = "type"
public static final String TYPE_POST = "post"
}
class Steps {
def load() {
// this method will call methods that will initialize each step definition.
// from the Gremlin REPL or other code base that utilizes the steps, simply
// call new Steps().load() to make the steps available.
}
}
class Steps {
def load() {
defineStepPost()
}
private def defineStepPost() {
Gremlin.defineStep('post', [Vertex, Pipe], { _().has(S.PROPERTY_TYPE, S.TYPE_POST) })
}
}
g.V.post
g.V.post.out('child').loop(1){it.loops<25}{true}
m=[:]
g.V.post.out('child').loop(1){it.loops<25}{true}
.path.groupBy(m){it[0].userName}{it}{it.collectMany{it}.unique()}.iterate()
class Steps {
public static final int CONTROL_MAX_DEPTH = 25
def load() {
defineStepPost()
defineStepPostTree()
defineStepFlattenThread()
}
private def defineStepPost() {
Gremlin.defineStep('post', [Vertex, Pipe], { _().has(S.PROPERTY_TYPE, S.TYPE_POST) })
}
private def defineStepPostTree() {
Gremlin.defineStep('postTree', [Vertex, Pipe], { depth = CONTROL_MAX_DEPTH ->
_().post.out(S.EDGE_CHILD).loop(1){it.loops<depth}{true} }) } private def defineStepFlattenThread() { // the addition of .transform{it[0]}.dedup to the end of this Gremlin statement // makes flattenThread a pure side-effect in that it converts the output back to // the original vertices passed in. Gremlin.defineStep('flattenThread', [Vertex, Pipe], { m, depth = CONTROL_MAX_DEPTH, keyOn = null ->
_().postTree(depth).path.groupBy(m){keyOn == null ? it[0] : keyOn(it[0])}{it}
{it.collectMany{it}.unique()}.transform{it[0]}.dedup
})
}
}
g.V.post
// traverses to the default depth of 25
g.V.postTree
// traverse to the assigned depth of 256
g.V.postTree(256)
m=[:];g.V.flattenThread(m).iterate()
// traverse to depth 256
m=[:];g.V.flattenThread(m, 256).iterate()
// traverse to depth 256, key the Map on the postId of the root vertex instead of the vertex itself
m=[:];g.V.flattenThread(m, 256, {it.getProperty(PROPERTY_POST_ID)}).iterate()