使用遍历框架

时间:2018-03-21 10:20:04

标签: neo4j neo4j-java-api neo4j-traversal-api

我目前正在开发一个图表,其中节点通过概率边连接。每条边上的权重定义了边缘存在的概率。

以下是一个开始使用的示例图表

(A)-[0.5]->(B)
(A)-[0.5]->(C)
(B)-[0.5]->(C)
(B)-[0.3]->(D)
(C)-[1.0]->(E)
(C)-[0.3]->(D)
(E)-[0.3]->(D)

我想使用Neo4j Traversal Framework从(A)开始遍历此图,并根据沿途找到的边的概率返回已到达的节点数。

重要提示:

  • 到达的每个节点只能计算一次。 - >如果(A)达到(B)和(C),则(C)不需要达到(B)。另一方面,如果(A)未达到(B)但达到(C)则(C)将尝试达到(B)。
  • 同样如果(B)到达(C),(C)将不再尝试并达到(B)。
  • 这是一个离散时间步长函数,一个节点只会尝试到达一个相邻节点。
  • 为了测试边缘的存在(我们是否遍历它),我们可以生成一个随机数并验证它是否小于边缘权重。

我已经编写了部分遍历描述,如下所示。 (这里可以从多个节点开始,但这不是解决问题所必需的。)

TraversalDescription traversal = db.traversalDescription()
            .breadthFirst()
            .relationships( Rels.INFLUENCES, Direction.OUTGOING )
            .uniqueness( Uniqueness.NODE_PATH )
            .uniqueness( Uniqueness.RELATIONSHIP_GLOBAL )
            .evaluator(new Evaluator() {

              @Override
              public Evaluation evaluate(Path path) {

                // Get current
                Node curNode = path.endNode();

                // If current node is the start node, it doesn't have previous relationship,
                // Just add it to result and keep traversing
                if (startNodes.contains(curNode)) {
                    return Evaluation.INCLUDE_AND_CONTINUE;
                }
                // Otherwise...
                else {
                  // Get current relationhsip
                  Relationship curRel = path.lastRelationship();

                  // Instantiate random number generator
                  Random rnd = new  Random();

                  // Get a random number (between 0 and 1)
                  double rndNum = rnd.nextDouble();


                  // relationship wc is greater than the random number
                  if (rndNum < (double)curRel.getProperty("wc")) {


                    String info = "";
                    if (curRel != null) {
                        Node prevNode = curRel.getOtherNode(curNode);
                        info += "(" + prevNode.getProperty("name") + ")-[" + curRel.getProperty("wc") + "]->";
                    }
                    info += "(" + curNode.getProperty("name") + ")";
                    info += " :" + rndNum;
                    System.out.println(info);

                    // Keep node and keep traversing
                    return Evaluation.INCLUDE_AND_CONTINUE;
                  } else {

                    // Don't save node in result and stop traversing
                    return Evaluation.EXCLUDE_AND_PRUNE;
                  }
                }
              }
            });

我跟踪到达的节点数量如下:

long score = 0;
for (Node currentNode : traversal.traverse( nodeList ).nodes())
{
    System.out.print(" <" + currentNode.getProperty("name") + "> ");
    score += 1;
}

此代码的问题在于虽然定义了NODE_PATH,但可能存在我不想要的循环。

因此,我想知道:

  • 是否有解决方案可以避免周期并准确计算到达的节点数量?
  • 理想情况下,可以(或更好)使用PathExpander执行相同的操作,如果是,我该如何进行编码?

由于

1 个答案:

答案 0 :(得分:0)

这当然不是最佳答案。

不是迭代在nodes()上,而是迭代路径,并将endNode()添加到集合中,然后简单地将集合的大小作为唯一节点的数量。

HashSet<String> nodes = new HashSet<>();
for (Path path : traversal.traverse(nodeList))
    {
        Node currNode = path.endNode();
        String val = String.valueOf(currNode.getProperty("name"));
        nodes.add(val);
        System.out.println(path);
        System.out.println("");
    }
    score = nodes.size();

希望有人能提出更优化的解决方案。

尽管NODE_PATH并没有阻止周期的形成,但我仍然感到惊讶。