我需要找到节点之间的最短路径,但是对良好路径中的关系类型有一些限制。
我有两种关系类型:A& B. 如果路径具有两个或更多类型B的连续关系,则该路径被认为是错误的:
良好路径:() - A->() - A->()< -A - () - B->() - A->() - B->()
错误路径:() - A->() - A->()< -A - () -B->()< -B - () - A- >()
Cypher查询:
MATCH path=allShortestPaths( (p:P{idp:123})-[rel:A|B*]-(p2:P{idp:124}) )
WHERE *some-predicate-on-path-or-rel*
RETURN path
不是解决方案,因为最短的好路径可能比最短的坏路径长。
Q1:一些Cypher查询可以解决这个问题吗?
我可以使用嵌入式Java Neo4J API解决我的问题:
GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase("db/store/dir/path");
TraversalDescription td = graphDb.traversalDescription()
.breadthFirst()
.evaluator(Evaluators.toDepth(max_depth))
.evaluator(Evaluators.endNodeIs(Evaluation.INCLUDE_AND_PRUNE, Evaluation.EXCLUDE_AND_CONTINUE, endNode))
.evaluator(new DoubleB_PruneEvaluator());
static class DoubleB_PruneEvaluator implements Evaluator {
@Override
public Evaluation evaluate(final Path path) {
Iterator<Relationship> lRels = path.reverseRelationships().iterator();
if (lRels.hasNext() && lRels.next().isType(MyRelTypes.B)) {
if (lRels.hasNext() && lRels.next().isType(MyRelTypes.B))
return Evaluation.EXCLUDE_AND_PRUNE;
}
return Evaluation.INCLUDE_AND_CONTINUE;
}
}
Q2:这个解决方案效率很高吗?或者如何改进?
但我的应用程序是用PHP编写的,并通过REST协议与Neo4j服务器进行交互。
问题3:如何通过某些REST查询运行此解决方案?
答案 0 :(得分:1)
没有聪明的人不会回答我。所以我会尝试自己。
A1:标准Cypher查询无法解决此问题。 (我的Neo4j版本3.1.1)
A2:由于以下几个原因,此解决方案效率不高:
此外,此解决方案只找到一条路径。不会找到相同长度的其他路径。
A3:可以通过extending Neo4j将Java编码的解决方案添加到服务器中。 我使用user-defined procedures解决了我的问题:
我/应用/ RelType.java:
package my.app;
import org.neo4j.graphdb.*;
public enum RelType implements RelationshipType {
A, B
}
我/应用/ DoubleB_PruneEvaluator.java:
package my.app;
import java.util.*;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.traversal.*;
public class DoubleB_PruneEvaluator implements Evaluator {
@Override
public Evaluation evaluate(final Path path) {
Iterator<Relationship> lRels = path.reverseRelationships().iterator();
if (lRels.hasNext() && lRels.next().isType(RelType.marry)) {
if (lRels.hasNext() && lRels.next().isType(RelType.marry))
return Evaluation.EXCLUDE_AND_PRUNE;
}
return Evaluation.INCLUDE_AND_CONTINUE;
}
}
我/应用/ Procedures.java:
package my.app;
import java.util.stream.Stream;
import org.neo4j.graphdb.*;
import org.neo4j.procedure.*;
import org.neo4j.graphdb.traversal.*;
public class Procedures {
@Context
public GraphDatabaseService db;
@Procedure
public Stream<PathHit> shortestWo2B(
@Name("from") Node fromNode,
@Name("to") Node toNode,
@Name("maxDepth") long maxDepth)
{
TraversalDescription td = db.traversalDescription()
.breadthFirst()
.relationships(RelType.A)
.relationships(RelType.B)
.evaluator(Evaluators.toDepth((int)maxDepth))
.evaluator(Evaluators.endNodeIs(Evaluation.INCLUDE_AND_PRUNE, Evaluation.EXCLUDE_AND_CONTINUE, toNode))
.evaluator(new DoubleB_PruneEvaluator());
return td.traverse(fromNode)
.stream()
.map( PathHit::new );
}
public static class PathHit {
public Path path;
public PathHit(Path path) {
this.path = path;
}
}
}
Doc:https://neo4j.com/docs/java-reference/3.1/javadocs/index.html?org/neo4j/procedure/Procedure.html
关于编译和安装插件的几句话:
作为Java的初学者,我认为Eclipse和Maven的实用程序太重了。我更喜欢使用简单的 javac &amp; 罐:
$ export CLASSPATH=/path/to/neo4j-install-dir/lib/*:.
$ javac my/app/*.java
$ jar -cf my-neo4j-plugin.jar my/app/*.class
$ cp my-neo4j-plugin.jar /path/to/neo4j-install-dir/plugins/
$ /path/to/neo4j-install-dir/bin/neo4j restart
现在我们可以运行Cypher查询:
MATCH (p1:P{idp:123})
MATCH (p2:P{idp:124})
CALL my.app.shortestWo2B(p1,p2,100) YIELD path
RETURN path;