我需要使用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以查找所有(最短)路径?
答案 0 :(得分:0)
一些建议:
了解shortestpath
和allshortestpths
actually implemented的方式。您可以修改代码副本以执行所需操作。
完全不使用TraversaDescription。
还有一个“实验性”BidirectionalTraversalDescription似乎更接近shortestpath
和allshortestpths
实现的设计。您也许可以使用它。
答案 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毫秒!