将 Gremlin Groovy 转换为 Gremlin Java 应该不是很困难。我总是反对你这样做:
- 大大增加代码的大小
- 让您的代码不那么可读
- 让您的代码更难维护
如果您在一个不会听说过外部编程语言的“Java 商店”工作,我认为仅通过几个 Gremlin 在 groovy 和 java 中的差异示例来向人们推销这些观点并不难(易于阅读一个衬里与可能是数百行代码的内容)。此外,Groovy 可以与 java 一起放入标准 Maven 项目中的同一模块中,也可以放入其他项目所依赖的单独独立模块中。在大多数情况下,我更喜欢后者,因为您将 groovy 隔离在一个包中,并且可以在多个用例中作为 DSL 重用(例如,应用程序、gremlin 控制台中的附加库等)。
也就是说,如果您仍然必须使用 Java,我仍然会从编写 Groovy 开始。使用 Gremlin 控制台并正确设置遍历算法。听起来好像您的两个用例都涉及循环,所以我们只会说您的遍历看起来像:
g.v(1).out.loop(1){true}{it.object.someProperty=="emitIfThis"}
所以这将从顶点“1”遍历链,直到我用完链,在第一个闭包中用“true”表示,然后在第二个闭包中发出符合我的标准的任何顶点。一旦定义和测试了这么多 Gremlin,就该转换为 Java。
如您所知,它以 GremlinPipeline 开头,第一部分很容易用于转换目的:
new GremlinPipeline(g.getVertex(1)).out()
如您所见,Groovy 方法几乎可以相当干净地映射到 Java,直到您需要闭包,loop 是需要闭包的步骤之一。要使用 Gremlin Java,您可能会发现查看 javadoc for GremlinPipeline 很有用。
我使用了loop 的三个参数版本 - 标记为“已弃用”的版本(但这对于我们的目的来说是可以的) - 你可以看到它here。第一个参数很简单 - 一个整数,所以翻译的第一部分是:
new GremlinPipeline(g.getVertex(1)).out().loop(1, closure, closure)
我已经为我们拥有的另外两个闭包留下了占位符。如果您这样看,它与我们的 Groovy 版本并没有太大区别——语法略有不同。
在 Java 8 之前,Java 语言中没有内置闭包的概念。请注意,在TinkerPop3 中,Gremlin 发生了巨大变化,以利用我们现在拥有 lambda 的事实。但是当你在 TinkerPop2 中时,你必须使用内置的 PipeFunction,它本质上代表了我们 groovy 闭包的类型化版本。循环的两个参数的PipeFunction 是:
PipeFunction<LoopPipe.LoopBundle<E>,Boolean>
所以基本上,这是一个将LoopPipe.LoopBundle 作为对象的函数,该对象包含有关循环的元数据并期望您返回一个布尔值。如果你理解了这个概念,那么所有 Gremlin Java 都会为你打开,因为你在任何地方看到一个 groovy 闭包,你都知道它下面只是 java 中的某种形式的 PipeFunction 并且鉴于你现在可以阅读来自 javadocs 的PipeFunction,进行这些语言翻译应该很简单。
我们要做的第一个闭包翻译非常简单——我们只需要我们的PipeFunction 来返回true:
new GremlinPipeline(g.getVertex(1)).out().loop(1,
new PipeFunction<LoopPipe.LoopBundle<Vertex>,Boolean>() {
public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
return true;
}
}, closure)
因此,对于loop 的第二个参数,我们必须构造一个新的PipeFunction,它有一个名为compute 的方法。从那个方法我们返回true。现在来处理控制要发射的顶点的第二个PipeFunction 参数:
new GremlinPipeline(g.getVertex(1)).out().loop(1,
new PipeFunction<LoopPipe.LoopBundle<Vertex>,Boolean>() {
public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
return true;
}
},
new PipeFunction<LoopPipe.LoopBundle<Vertex>,Boolean>() {
public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
return argument.getObject().getProperty("someProperty").equals("emitIfThis");
}
})
这就是转换。由于这篇文章很长,让我们将原始的 groovy 放在更靠近上面的地方,以便清楚区别:
g.v(1).out.loop(1){true}{it.object.someProperty=="emitIfThis"}
在原本非常简单的遍历上,我们从上面的一行代码变成了近十行代码。 Gremlin Java 在 TinkerPop3 中使用 lambda 并对语言本身进行了重大改革,但这些早期版本生成的 Java 代码确实不值得在 Groovy 可以使事情变得非常整洁时生成或维护。