4

我有一个用例,我必须遍历从特定顶点开始的顶点链。它是一个线性链(如火车),只有一个顶点连接到前一个顶点。遍历时,我必须根据某些标准发出某些顶点,直到到达链的末端。

第二个用例是上述用例的扩展,但不是从单个顶点开始的单个链,而是有多个这样的链,同样从单个顶点开始。我必须遍历每个链并检查顶点中的特定属性值。当找到该属性匹配时,我必须发出该顶点并从第二个链开始,依此类推。

我必须使用 Gremlin java API 来实现。这似乎很简单,但我是 gremlin 的新手,并且在 gremlin java API 上也没有太多来自互联网的帮助。

4

1 回答 1

11

将 Gremlin Groovy 转换为 Gremlin Java 应该不是很困难。我总是反对这样做:

  1. 大大增加代码的大小
  2. 降低代码的可读性
  3. 让你的代码更难维护

如果您在一个不会听说过外部编程语言的“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。

如您所知,以 a 开头,GremlinPipeline第一部分很容易用于转换目的:

new GremlinPipeline(g.getVertex(1)).out()

如您所见,Groovy 方法几乎可以相当干净地映射到 Java,直到您需要闭包并且loop是需要闭包的步骤之一。要使用Gremlin Java,您可能会发现查看GremlinPipeline.

我使用了三个参数版本loop- 一个标记为“已弃用”的版本(但这对于我们的目的来说是可以的) - 你可以在这里看到它。第一个参数很简单 - 一个整数,所以翻译的第一部分是:

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>

所以基本上,这是一个将 aLoopPipe.LoopBundle作为对象的函数,其中包含有关循环的元数据,并期望您返回一个布尔值。如果你理解了这个概念,那么所有 Gremlin Java 都会为你打开,因为你在任何地方看到一个 groovy 闭包,你就知道它下面只是PipeFunctionjava 中的某种形式,并且你现在可以PipeFunction从javadocs,做这些语言翻译应该很简单。

我们要做的第一个闭包翻译很简单——我们只需要我们PipeFunction的 return 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我们必须构造一个 new 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 中得到了它自己的 lambdas 和对语言本身的大修,但是当 Groovy 可以使事情变得非常整洁时,这些以前的版本产生的 Java 代码真的不值得努力生成或维护。

于 2015-04-02T11:20:34.473 回答