1

考虑我有以下带有边权重的图表:

在此处输入图像描述

我想知道我是否可以使用 CYPHER 执行从节点 a 开始的遍历,并按照边的权重顺序递增。这是上面它应该返回(a)-4->(e)-3->(c)-3->(d)

这可以使用密码吗?

4

2 回答 2

4

正如@FrankPavageau 所说,用Java 编写解决方案可能会更简单、更快。然而,通过利用现有的 APOC 过程apoc.periodic.commit,您不必在 Java 中实现任何东西。

apoc.periodic.commit将重复执行 Cypher 查询,直到它返回值 0 或根本没有结果。这是一个如何使用它来解决您的问题的示例。

首先,让我们创建您的示例数据:

CREATE (a:Foo {id: 'a'}), (b:Foo {id: 'b'}), (c:Foo {id: 'c'}), (d:Foo {id: 'd'}), (e:Foo {id: 'e'}), (f:Foo {id: 'f'}), (g:Foo {id: 'g'}),
  (a)-[:NEXT {value: 3}]->(b),
  (a)-[:NEXT {value: 4}]->(e),
  (e)-[:NEXT {value: 3}]->(c),
  (e)-[:NEXT {value: 1}]->(f),
  (e)-[:NEXT {value: 2}]->(g),
  (c)-[:NEXT {value: 3}]->(d),
  (c)-[:NEXT {value: 2}]->(g);

此技术涉及您的 3 个查询:

  1. 用于创建带有Temp标签的临时节点的查询(在下面的步骤 2 中执行的重复执行之间保持状态,并保存最终结果)。(在样本数据中,起始节点有一个ida

    MERGE (temp:Temp)
    SET temp = {values: [], ids: ['a']};
    
  2. 调用apoc.periodic.commit以执行传递的 Cypher 语句的重复执行的查询。每次执行 Cypher 语句时,它都会从最后找到的节点(位于id末尾的temp.ids节点)开始,并尝试找到关系具有最高value值的下一个节点。如果最后一个节点是叶节点,则 Cypher 语句不返回任何内容(因为第二个节点MATCH将失败,因此中止该语句)——这将终止该过程;否则,Cypher 语句会将max值附加到temp.values和对应的节点idtemp.ids,并返回 1。

    CALL apoc.periodic.commit("
      MATCH (temp:Temp)
      MATCH (:Foo {id: LAST(temp.ids)})-[n:NEXT]->(f:Foo)
      WITH temp, REDUCE(s = {max: 0}, x IN COLLECT({v: n.value, id: f.id}) |
        CASE WHEN x.v > s.max
          THEN {max: x.v, id: x.id}
          ELSE s
        END
      ) AS curr
      SET temp.values = temp.values + curr.max, temp.ids = temp.ids + curr.id
      RETURN 1;
    ", NULL);
    
  3. 获取最终结果的查询。ids集合将是沿“最大路径”的节点的 id,集合values将是沿同一路径values的关系的 id。NEXT

    MATCH (temp:Temp)
    RETURN temp;
    

结果如下:

╒══════════════════════════════════════╕
│temp                                  │
╞══════════════════════════════════════╡
│{values: [4, 3, 3], ids: [a, e, c, d]}│
└──────────────────────────────────────┘
于 2016-11-29T02:43:08.187 回答
2

Your description is slightly wrong (based on your example), as you don't want to traverse relationships with an increasing weight, you want to traverse the relationship(s) with the maximum weight at each step.

You can't do it in a generic way in Cypher, because the result is built iteratively, and you can't know the maximum length of a result path.

In Cypher, you'd have to

  1. build all the paths
  2. filter them by the weight of the first relationship
  3. filter the remaining ones by the weight of the second relationship (it if exists)
  4. etc.

The declarative nature of Cypher is not really compatible: it would be cumbersome, and probably slow as well. It would be much easier to build a procedure or function (in the upcoming Neo4j 3.1) traversing the longest path(s), with the PathExpander only returning the relationships with the maximum weight from the current node.

于 2016-11-28T13:13:45.793 回答