Neo4j Cypher:除了常规排序之外还有拓扑排序?

时间:2014-04-29 23:44:24

标签: graph neo4j cypher

假设我有一个看起来像这样的节点树:

enter image description here

数字对应于某些值,我通常希望按排序。 (可能是时间,它可能是某种分数,无论如何。)

如果我按照这个数字排序它们,我当然会得到这样的结果:

1, 2, 3, 4, 5, 6, 7, 8, 9

这通常很好,但除此之外,我还想应用父母总是在孩子面前排序的约束。所以我真正想要的是这种:

3, 2, 1, 4, 5, 6, 7, 8, 9

你可以看到这看起来几乎一样;我们刚刚将1, 2, 3的顺序翻转为3, 2, 1

有没有办法通过Neo4j Cypher查询实现此类排序?

-

这是一个实时控制台示例,可以使用此树进行播放:

http://console.neo4j.org/r/l9mav2

到目前为止,这是我的查询:

MATCH path=( ({i: 3}) <-[:parent*0..]- (node) )
RETURN node, node.i, LENGTH(path)

我只是不确定如何使用此信息:

  • 如果我ORDER BY node.i,我会得到第一种。

  • 如果我ORDER BY LENGTH(path),那就太激进了。例如。 9之前的5, 6, 7, 8

  • 将两者按任意顺序组合起来也不起作用。

这可能吗?谢谢!

3 个答案:

答案 0 :(得分:2)

您可以将两个值组合起来表示您的排序顺序,只是为父母提供更高的优先级:

MATCH path =((root:Node { i: 3 })<-[:parent*0..]-(node:Node))
RETURN node, node.i, LENGTH(path)
ORDER BY LENGTH(path)+ node.id *10

http://console.neo4j.org/r/ijeqlv

返回

+--------------------------------------+
| node         | node.i | LENGTH(path) |
+--------------------------------------+
| Node[3]{i:3} | 3      | 0            |
| Node[2]{i:2} | 2      | 1            |
| Node[1]{i:1} | 1      | 2            |
| Node[4]{i:4} | 4      | 1            |
| Node[5]{i:5} | 5      | 2            |
| Node[6]{i:6} | 6      | 2            |
| Node[7]{i:7} | 7      | 2            |
| Node[8]{i:8} | 8      | 3            |
| Node[9]{i:9} | 9      | 1            |
+--------------------------------------+
9 rows
32 ms

答案 1 :(得分:2)

这感觉有点hacky,但也许它会起作用,这取决于树的大小是多么可预测:

MATCH path=(root:Node { i: 3 })<-[:parent*0..]-(node:Node)
WITH nodes(path)[-1] as n,[x IN nodes(path)| x.i] AS o
ORDER BY o[0], coalesce(o[1], -1), coalesce(o[2], -1), coalesce(o[3], -1) // and so forth
RETURN n

合并中的-1绝对低于.i属性中的任何可能值。

以下是使用字符串比较属性的另一个想法:

MATCH path=(root:Node { i: 3 })<-[:parent*0..]-(node:Node)
WITH nodes(path)[-1] AS n,[x IN nodes(path)| x.i] AS o, 
     reduce(maxLen=0, p IN root<-[:parent*]-()|CASE WHEN maxLen < length(p)
                                                   THEN length(p)
                                                   ELSE maxLen END ) AS maxLen
ORDER BY reduce(acc='', x IN range(0,maxLen)|acc+coalesce(str(o[x]), ''))
RETURN n,reduce(acc='', x IN range(0,maxLen)|acc+coalesce(str(o[x]), ''))

您可以获得所示的最大路径长度,或者只是将maxLen设为非常高的数字。

答案 2 :(得分:0)

我没有Neo4j的经验,但如果我理解正确,下面的算法,用文字来说,符合你的描述。祝你好运!

从根节点开始,将根复制到排序列表中作为下一个值。在root的子节点中进行选择,选择“next root”作为root的子节点中最小的一个。用“next root”替换root,并将所有“next root”的子项移动到一个级别。重复,直到图表为空。

例如:

Sorted = {}
           3
        /  |  \
       2   4   9
       |  /|\
       1 5 6 7
             |
             8
Sorted = {3}
       2
     / | \
    1  4  9
      /|\
     5 6 7
         |
         8
Sorted = {3,2}
       1
       | \
       4  9
      /|\
     5 6 7
         |
         8
Sorted = {3,2,1}
         4  
      / / \  \
     5 6   7  9
           |
           8
Sorted = {3,2,1,4}
          5  
        / | \
       6  7  9
          |
          8
Sorted = {3,2,1,4,5}
         6  
        /  \
       7    9
       |
       8
Sorted = {3,2,1,4,5,6}
         7  
        /  \
       8    9
Sorted = {3,2,1,4,5,6,7}
          8  
          |
          9
Sorted = {3,2,1,4,5,6,7,8}
          9
Sorted = {3,2,1,4,5,6,7,8,9}