【问题标题】:Returning unique paths with Gremlin in Java在 Java 中使用 Gremlin 返回唯一路径
【发布时间】:2016-02-04 10:34:13
【问题描述】:

我遇到了 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
  • 关注所有指向 X 的出站链接
  • 删除任何带有循环的路径(例如 A -> B-> C -> D-> B-> E)
  • 循环回到 X 最多 8 次,但是如果路径到达结束节点,则停止该路径进一步前进。
  • 重新检查循环路径。
  • 过滤除 endNode 之外的路径。
  • 填充列表。

据此,我目前收到以下不需要的行为 - 重复的路径 - 到达 endNodeID 但继续的路径。

虽然我之后可以在代码中更正此问题(在一次模拟中,它从 10000 条路径更正为仅 200 条),但这似乎是一种资源浪费。

任何帮助将不胜感激。

【问题讨论】:

    标签: java groovy gremlin


    【解决方案1】:

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

    示例图:

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

    以下代码产生路径

    • v1->v2->v4
    • v1->v3->v4
    • v1->v3->v2->v4

    Gremlin 管道:

    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;
    }
    

    【讨论】:

    • 谢谢。我已经使用了它,并进行了一些调整,我设法让它工作并修改它以实现 Dijkstra 的算法。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多