在Java中使用Gremlin返回唯一路径

时间:2016-02-04 10:34:13

标签: java groovy gremlin

我遇到了Gremlin返回重复路径的问题,我想知道是否有人可以帮助我。如果我犯了任何简单的错误,我对Gremlin很陌生。

我的数据库的一个简单形式包括超过50个节点和超过5000个边缘,其中边缘被认为是一个方向,但是在两个节点之间可能存在两个方向的边缘导致循环结构(因此节点A - > B - > ; A),同样你可以(A - > B - > C - > A)。

我想要完成的是遍历网络,返回起始节点和结束节点之间的每条唯一路径,它没有循环。下面是我的代码示例。

final List<List> paths = new ArrayList<List>();
String endNodeID = endNode.getVertex().getId().toString();
new GremlinPipeline<Vertex, ArrayList<Vertex>>(startNode.getVertex())
    .as("x").out("OutboundLink").simplePath()
    .loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
                @Override
                public Boolean compute(final LoopPipe.LoopBundle<Vertex> loopBundle) {
                    return loopBundle.getLoops() <= 8;
                }
            }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
                @Override
                public Boolean compute(final LoopPipe.LoopBundle<Vertex> loopBundle) {
                    return endNodeID.equals(loopBundle.getObject().getId().toString());
                }
            }).simplePath().filter(new PipeFunction<Vertex, Boolean>() {

                @Override
                public Boolean compute(final Vertex arg0) {
                    return targetId.equals(arg0.getId().toString());
                }
            }).path(new PipeFunction<Vertex, String>() {
                @Override
                public String compute(final Vertex vertex) {
                    return vertex.getId().toString();
                }
            }).fill(paths);

我相信它的确如此

  • 获取起始顶点
  • 将位置声明为X
  • 关注所有OutboundLinks到X
  • 删除任何具有循环的路径(例如A - > B-> C - > D-> B-> E)
  • 最多循环回X到8次,但是如果路径到达终点节点,则停止该路径进一步前进。
  • 重新检查周期性路径。
  • 过滤路径,而不是在endNode结束。
  • 填充列表。

由此我正在获得以下不良行为   - 重复路径   - 命中endNodeID但已继续的路径。

虽然我之后可以在代码中纠正这个问题(在一次模拟中,它从10000个路径纠正到只有200个),但这似乎是浪费资源。

非常感谢任何协助。

1 个答案:

答案 0 :(得分:2)

使用Titan 0.5.4我也没有让simplePath()为我工作。 API文档表明它的目的是检测和过滤掉循环路径,但可能是对我的误解。我最终得到的是编写自己的循环检测代码。

示例图:

            +--+        
     +------+V1+------+ 
     |      +--+      | 
     v                | 
              ^       | 
     +--+     |       v 
     |V2+-----+          
     |  |            +--+
     +--+ <----------+V3|
     |               ++-+
     |                | 
     |                | 
     |                | 
     |      +--+      | 
     +----> |V4| <----+ 
            +--+            

以下代码生成路径

  • V1-&GT; V2-&GT; V4
  • V1-&GT; V3-&GT; V4
  • V1-&GT; V3-&GT; V2-&GT; V4

Gremlin Pipeline:

public static List<List<Element>> findPathsBetweenSimple(final Vertex from, final Vertex to) {
    final Object endID = to.getId();
    GremlinPipeline<Vertex, List<Element>> pipe = new GremlinPipeline<>(from);
    pipe.as("startAt")
            .out()
            .loop("startAt", new PipeFunction<LoopBundle<Vertex>, Boolean>() {
                @SuppressWarnings("unchecked")
                @Override
                public Boolean compute(LoopBundle<Vertex> lb) {
                    Boolean doContinue = Boolean.TRUE;
                    LOG.trace("Loop cnt: " + lb.getLoops() + "; Vertex: " + lb.getObject());
                    if (containsLoop(lb.getPath(), lb.getObject())) {
                        LOG.debug("Loop detected in path. Aborting. " + lb.getPath());
                        doContinue = Boolean.FALSE;
                    } else if (endID.equals(lb.getObject().getId())) {
                        LOG.debug("Path found: " + lb.getPath() + ", " + lb.getObject());
                        doContinue = Boolean.FALSE;
                    }
                    return doContinue;
                }
            })
            .has("id", endID)
            .path();
    return pipe.toList();
}

循环检测:

private static boolean containsLoop(final List<Element> path, Vertex current) {
    boolean loopDetected = false;

    final List<Vertex> vPath = new ArrayList<>();
    for (Element element : path) {
        if (element instanceof Vertex) {
            vPath.add((Vertex) element);
        }
    }
    vPath.add(current);

    for (Vertex v : vPath) {
        if (Collections.frequency(vPath, v) > 1) {
            loopDetected = true;
            break;
        }
    }

    return loopDetected;
}