【问题标题】:GremlinPipeLine java API chain traversal in Titan graph use casesTitan图用例中的GremlinPipeLine java API链遍历
【发布时间】:2015-04-02 09:14:44
【问题描述】:

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

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

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

【问题讨论】:

标签: java titan gremlin graph-traversal


【解决方案1】:

将 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。

如您所知,它以 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 可以使事情变得非常整洁时生成或维护。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    相关资源
    最近更新 更多