Titan 图用例中的 GremlinPipeLine java API 链遍历

GremlinPipeLine java API chain traversal in Titan graph use cases

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

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

我必须使用 Gremlin java API 来实现。这看起来很简单,但我是 gremlin 的新手,而且在 gremlin java API.

上也没有太多来自互联网的帮助

将 Gremlin Groovy 转换为 Gremlin Java 应该不是很困难。我总是反对按照你的意愿去做:

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

如果您在 "Java shop" 工作,不会听说外部编程语言,我认为仅通过几个 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 的三参数版本 - 标记为 "deprecated" 的版本(但这对我们的目的来说没问题) - 你可以看到它 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 作为对象的函数,该对象包含有关循环的元数据,并期望您 return 一个布尔值。如果你理解这个概念,那么所有的 Gremlin Java 都会为你打开,因为在你看到 groovy 闭包的任何地方,你都知道它下面只是 PipeFunction 中的某种形式 java 鉴于您现在可以从 java 文档中阅读 PipeFunction 的期望,进行这些语言翻译应该很简单。

我们要做的第一个闭包转换非常简单——我们只需要 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 的第二个参数,我们必须构造一个新的 PipeFunction,它有一个名为 compute 的方法。从那个方法我们 return 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");
        }
    })

还有转换。因为这是一个很长的post,让我们把原来的groovy放在离上面更近的地方,这样区别就很明显了:

g.v(1).out.loop(1){true}{it.object.someProperty=="emitIfThis"}

我们从上面的一行代码变成了将近一打代码,这是一个非常简单的遍历。 Gremlin Java 在 TinkerPop3 中发挥了作用,给定了 lambda 表达式和对语言本身的重大改革,但这些先前版本产生的 java 代码确实不值得在 [=88= 时生成或维护] 可以把东西弄的很整洁