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

时间:2015-04-02 09:14:44

标签: java titan gremlin graph-traversal

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

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

我必须使用Gremlin java API实现这一点。这看起来很简单,但我是gremlin的新手,并且在gremlin java API上没有太多关于互联网的帮助。

1 个答案:

答案 0 :(得分:10)

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

  1. 大大增加代码的大小
  2. 使您的代码不易阅读
  3. 让您的代码更难维护
  4. 如果你在一个不会听到外部编程语言的“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,您可能会发现查看GremlinPipeline的{​​{3}}非常有用。

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

    new GremlinPipeline(g.getVertex(1)).out().loop(1, closure, closure)
    

    我已经把占位符留给了我们拥有的另外两个封口。如果以这种方式看待它,它与我们的Groovy版本没有什么不同 - 语法略有不同。

    在Java 8之前,没有内置于java语言中的闭包概念。请注意,在here中,Gremlin已经发生了巨大变化,以利用我们现在拥有lambda的事实。但是当你在TinkerPop2中时,你必须使用内置的PipeFunction,它基本上代表我们的groovy闭包的类型版本。循环的两个参数的PipeFunction是:

    PipeFunction<LoopPipe.LoopBundle<E>,Boolean>
    

    基本上,这是一个函数,它将LoopPipe.LoopBundle作为一个对象,它包含有关循环的元数据,并期望返回一个布尔值。如果你理解了这个概念,那么所有的Gremlin Java都会为你打开,因为在你看到一个groovy闭包的任何地方,你知道它下面只是某种形式的PipeFunction在java中,并且你现在可以阅读来自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中自成一体,给出了lambdas并对语言本身进行了重大改革,但是这些先前的版本产生的Java代码在Groovy可以使事情变得非常整洁时非常值得生成或维护。