【问题标题】:Neo4J: shortest paths with specific relation types sequence constrainNeo4J:具有特定关系类型序列约束的最短路径
【发布时间】:2017-08-17 14:18:49
【问题描述】:

我需要找到节点之间的最短路径,但在良好路径中对关系类型有一些限制。

我有两种关系类型:A 和 B。 如果路径有两个或多个 B 类型的连续关系,则该路径被认为是错误的:

好的路径:()-A->()-A->()()-A->()-B->()
错误路径:()-A->()-A->()-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 服务器交互。

Q3:如何通过一些 REST 查询来运行这个解决方案?

【问题讨论】:

    标签: neo4j cypher shortest-path


    【解决方案1】:

    没有聪明人不会回答我。那我自己试试吧。

    A1:标准的 Cypher 查询无法解决此问题。 (我的 Neo4j 版本 3.1.1)

    A2:这个解决方案效率不高有几个原因:

    1. 标准函数shortestPath是通过使用more实现的 高效的双向 BFS。
    2. 此遍历描述不包含停止条件 找到了解决方案。遍历将一直持续到最大值 深度。

    此外,此解决方案仅找到一条路径。将找不到其他相同长度的路径。

    A3:extending Neo4j 可以将 Java 编码的解决方案添加到服务器。 我使用user-defined procedures 解决了我的问题:

    我的/app/RelType.java:

    package my.app;
    
    import org.neo4j.graphdb.*;
    
    public enum RelType implements RelationshipType {
        A, B
    }
    

    我的/app/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;
        }
    }
    

    我的/app/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;
            }
        }
    }
    

    文档:https://neo4j.com/docs/java-reference/3.1/javadocs/index.html?org/neo4j/procedure/Procedure.html

    关于编译安装插件的几句话:

    作为 Java 初学者,我认为 Eclipse 和 Maven 实用程序太重了。我更喜欢使用简单的javac & jar

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-21
      • 2021-03-11
      • 1970-01-01
      • 1970-01-01
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多