使用TraversalDescription查找所有最短路径

时间:2017-04-07 17:01:04

标签: java neo4j graph-traversal

我需要使用TraversalDescription找到两个节点之间的所有最短路径。

(我不能使用Cypher过程allShortestPaths()因为我需要稍后添加一些特定的求值程序: Neo4J: shortest paths with specific relation types sequence constrain

Node startNode = ...;
Node endNode = ...;
TraversalDescription td = graphDb.traversalDescription()
    .breadthFirst()
    .evaluator(Evaluators.endNodeIs(Evaluation.INCLUDE_AND_PRUNE,
                                    Evaluation.EXCLUDE_AND_CONTINUE,
                                    endNode));

for (Path path : td.traverse(startNode)) {
    // only 1 path found
}

我只有一条路。

但如果我运行Cypher查询:

MATCH (startNode{...})
MATCH (endNode{...})
MATCH path = allShortestPaths((startNode)-[*]-(endNode))
RETURN path;

为同一个startNode和endNode找到了多条路径。

如何设置TraversalDescription以查找所有(最短)路径?

3 个答案:

答案 0 :(得分:0)

一些建议:

  1. 了解shortestpathallshortestpths actually implemented的方式。您可以修改代码副本以执行所需操作。 完全不使用TraversaDescription

  2. 还有一个“实验性”BidirectionalTraversalDescription似乎更接近shortestpathallshortestpths实现的设计。您也许可以使用它。

答案 1 :(得分:0)

问题的根源是“修剪”。当您找到带有endPoint的第一个路径时,您将停止遍历。所以试试这个:

TraversalDescription td = graphDb.traversalDescription()
    .breadthFirst()
    .evaluator(Evaluators.endNodeIs(Evaluation.INCLUDE_AND_CONTINUE,
                                    Evaluation.EXCLUDE_AND_CONTINUE,
                                    endNode));

答案 2 :(得分:0)

由于默认Uniqueness.NODE_GLOBAL,我的TraversalDescription无法用于查找多个路径:一旦发现,将永远不会再访问终端节点。

所以,第一步是:

td = td.uniqueness(Uniqueness.NODE_PATH);

但是现在我们没有停止条件,并且遍历不仅返回最短路径。

第二步是添加带来停止条件的路径评估器:

class EndNodeAndNotDeeperEvaluator implements Evaluator
{
    int depth = Integer.MAX_VALUE;
    Node endNode;

    public EndNodeAndNotDeeperEvaluator(Node node) {
        endNode = node;
    }

    @Override
    public Evaluation evaluate(Path path) {
        if (path.length() > depth)
            return Evaluation.EXCLUDE_AND_PRUNE;

        if (path.endNode().equals(endNode)) {
            depth = path.length();
            return Evaluation.INCLUDE_AND_PRUNE;
        }

        return Evaluation.EXCLUDE_AND_CONTINUE;
    }
}

td = td.evaluator(new EndNodeAndNotDeeperEvaluator(endNode));

现在它有效! ...用于短路径(长度<10)
但是对于更长的路径,它不会给出任何结果,但会给出OutOfMemoryException。

这是因为很多明显不是最短的路径正在被调查。

第3步:我们需要确保在以前的级别没有遇到每个中间节点:

public class EndNodeAndNotDeeperEvaluator implements Evaluator
{
    private Node endNode;
    private Map<Long,Integer> nodeDepths = new HashMap(100000);

    public EndNodeAndNotDeeperEvaluator(Node node) {
        endNode = node;
    }

    @Override
    public Evaluation evaluate(Path path) {
        Node pEndNode = path.endNode();

        Integer nodeDepth = nodeDepths.get(pEndNode.getId());
        if (nodeDepth == null) {
            nodeDepths.put(pEndNode.getId(), path.length());
        }
        else if (path.length() > nodeDepth) {
            return Evaluation.EXCLUDE_AND_PRUNE;
        }

        if (pEndNode.equals(endNode)) {
            //System.err.println(" map.size="+nodeDepths.size());
            return Evaluation.INCLUDE_AND_PRUNE;
        }

        return Evaluation.EXCLUDE_AND_CONTINUE;
    }
}

现在可行用于我拥有的所有最短路径 但不是很快 ...对于最长的路径(长度= 81),它需要大约6700ms ...
虽然Uniqueness.NODE_GLOBAL的常规遍历需要550毫秒(仅找到第一条路径); 内置GraphAlgoFactory.shortestPath(...).findAllPaths(...)需要90毫秒!