Neo4j 如何先序列化节点深度?

Neo4j 如何先序列化节点深度?,neo4j,neo4j-apoc,Neo4j,Neo4j Apoc,我正在学习Neo4J 我知道如何对节点进行深度优先搜索,但在我的例子中,我希望序列化所有节点,但要完全遍历一个分支,然后移动到下一个分支,依此类推 给定这些节点: N1 { order: 1 } N2 { order: 1 } N4 { order: 1 } N5 { order: 1 } N6 { order: 2 } N3 { order: 2 } N7 { order: 1 } 节点之间的关系是一种定向关系,名为的第u部分。E.i.N2-[

我正在学习Neo4J

我知道如何对节点进行深度优先搜索,但在我的例子中,我希望序列化所有节点,但要完全遍历一个分支,然后移动到下一个分支,依此类推

给定这些节点:

N1 { order: 1 }
  N2 { order: 1 }
    N4 { order: 1 }
      N5 { order: 1 }
      N6 { order: 2 }
  N3 { order: 2 }
    N7 { order: 1 }
节点之间的关系是一种定向关系,名为的第u部分。E.i.
N2-[part of]->N1

我希望列表按以下顺序序列化:
N1 N2 N4 N5 N6 N3 N7

最有效的方法是什么

提前谢谢


//E

您现在可能已经在Neo4j Graph Algorithms插件中发现了
algo.dfs.stream
函数,这在某种程度上让您走到了一半:

MATCH (startNode: Node { name: 'N1' } )
CALL algo.dfs.stream('Node', 'PART_OF', 'BOTH', id(startNode))
YIELD nodeIds 
UNWIND nodeIds as nodeId
WITH algo.asNode(nodeId) as n
RETURN n
问题是
algo.dfs.stream
不允许您控制在兄弟节点之间遍历节点的顺序-您最好的选择可能是在应用程序代码中这样做,因为编写dfs非常简单

然而,在过去的几个小时里,我用了一种纯密码的方法,通过你的
order
属性执行深度优先搜索,并以稳定的顺序进行排序。我由衷地恳求您不要使用此代码,原因如下:

  • 我很确定它在树中的节点数上至少有O(n^2)的复杂性
  • 大量昂贵的工作是作为单个批处理预先计算路径,而您自己的遍历代码可能是基于流的——这在大型图上不起作用
  • “仅仅因为你可以,并不意味着你应该”
但不把它贴在某个地方似乎是浪费,所以我们就在这里

假设一些测试数据与您的样本相匹配:

MERGE (n1: Node { order: 1, name: 'N1' })
MERGE (n2: Node { order: 1, name: 'N2' })
MERGE (n3: Node { order: 2, name: 'N3' })
MERGE (n4: Node { order: 1, name: 'N4' })
MERGE (n5: Node { order: 1, name: 'N5' })
MERGE (n6: Node { order: 2, name: 'N6' })
MERGE (n7: Node { order: 1, name: 'N7' })
MERGE (n2)-[:PART_OF]->(n1)
MERGE (n4)-[:PART_OF]->(n2)
MERGE (n5)-[:PART_OF]->(n4)
MERGE (n6)-[:PART_OF]->(n4)
MERGE (n3)-[:PART_OF]->(n1)
MERGE (n7)-[:PART_OF]->(n3)
下面将生成DFS遍历,其中通过对节点的
order
属性排序来选择同级节点

MATCH (root: Node { name: 'N1' }), pathFromRoot=shortestPath((root)<-[:PART_OF*]-(leaf: Node)) WHERE NOT ()-[:PART_OF]->(leaf)
WITH nodes(pathFromRoot) AS pathFromRootNodes
WITH pathFromRootNodes, reduce(pathString = "", pathElement IN pathFromRootNodes | pathString + '/' + right("00000" + toString(pathElement.order), 6)) AS orderPathString ORDER BY orderPathString
WITH reduce(concatPaths = [], p IN collect(pathFromRootNodes) | concatPaths + p) AS allPaths
WITH reduce(distinctNodes = [], n IN allPaths | CASE WHEN n IN distinctNodes THEN distinctNodes ELSE distinctNodes + n end) AS traversalOrder
RETURN [x in traversalOrder | x.name]
MATCH(根:节点{name:'N1'}),pathFromRoot=shortestPath((根)(叶)
将节点(pathFromRoot)作为pathFromRootNodes
使用pathFromRootNodes,将pathFromRootNodes | pathString+'/'+右侧(“00000”+toString(pathElement.order),6)中的pathElement按orderPathString顺序减少为orderPathString
使用reduce(concatPaths=[],collect(pathFromRootNodes)| concatPaths+p)中的p作为所有路径
以reduce(distinctNodes=[],n在所有路径中|当n在distinctNodes中时,则distinctNodes,否则distinctNodes+n end)作为遍历顺序
返回[x在遍历顺序中| x.name]
我不会逐行解释,但要点是:

  • 我们构建从根到每个叶节点的路径集
  • 对于每个路径,我们构造一个合成键,该键在每个节点处组合
    order
    属性,通过该键对路径进行排序,得到到达每个叶节点的顺序
    • 这可能是最重要的一位——我们填充了“order”属性,这样我们就可以在路径上使用词汇ASCII排序来生成遍历顺序
  • 我们展平排序路径列表,并消除其中的节点重复,以获得遍历顺序

您现在可能已经在Neo4j Graph Algorithms插件中发现了
algo.dfs.stream
函数,这在某种程度上让您走到了一半:

MATCH (startNode: Node { name: 'N1' } )
CALL algo.dfs.stream('Node', 'PART_OF', 'BOTH', id(startNode))
YIELD nodeIds 
UNWIND nodeIds as nodeId
WITH algo.asNode(nodeId) as n
RETURN n
问题是
algo.dfs.stream
不允许您控制在兄弟节点之间遍历节点的顺序-您最好的选择可能是在应用程序代码中这样做,因为编写dfs非常简单

然而,我在过去的几个小时里一直在使用纯密码的方法进行黑客攻击,这种方法通过你的
order
属性执行深度优先搜索,并以稳定的顺序进行排序。我由衷地恳请你不要使用此代码,原因如下:

  • 我很确定它在树中的节点数上至少有O(n^2)的复杂性
  • 大量昂贵的工作是作为单个批处理预先计算路径,而您自己的遍历代码可能是基于流的——这在大型图上不起作用
  • “仅仅因为你可以,并不意味着你应该”
但不把它贴在某个地方似乎是浪费,所以我们就在这里

假设一些测试数据与您的样本相匹配:

MERGE (n1: Node { order: 1, name: 'N1' })
MERGE (n2: Node { order: 1, name: 'N2' })
MERGE (n3: Node { order: 2, name: 'N3' })
MERGE (n4: Node { order: 1, name: 'N4' })
MERGE (n5: Node { order: 1, name: 'N5' })
MERGE (n6: Node { order: 2, name: 'N6' })
MERGE (n7: Node { order: 1, name: 'N7' })
MERGE (n2)-[:PART_OF]->(n1)
MERGE (n4)-[:PART_OF]->(n2)
MERGE (n5)-[:PART_OF]->(n4)
MERGE (n6)-[:PART_OF]->(n4)
MERGE (n3)-[:PART_OF]->(n1)
MERGE (n7)-[:PART_OF]->(n3)
下面将生成DFS遍历,其中通过对节点的
order
属性排序来选择同级节点

MATCH (root: Node { name: 'N1' }), pathFromRoot=shortestPath((root)<-[:PART_OF*]-(leaf: Node)) WHERE NOT ()-[:PART_OF]->(leaf)
WITH nodes(pathFromRoot) AS pathFromRootNodes
WITH pathFromRootNodes, reduce(pathString = "", pathElement IN pathFromRootNodes | pathString + '/' + right("00000" + toString(pathElement.order), 6)) AS orderPathString ORDER BY orderPathString
WITH reduce(concatPaths = [], p IN collect(pathFromRootNodes) | concatPaths + p) AS allPaths
WITH reduce(distinctNodes = [], n IN allPaths | CASE WHEN n IN distinctNodes THEN distinctNodes ELSE distinctNodes + n end) AS traversalOrder
RETURN [x in traversalOrder | x.name]
MATCH(根:节点{name:'N1'}),pathFromRoot=shortestPath((根)(叶)
将节点(pathFromRoot)作为pathFromRootNodes
使用pathFromRootNodes,将pathFromRootNodes | pathString+'/'+右侧(“00000”+toString(pathElement.order),6)中的pathElement按orderPathString顺序减少为orderPathString
使用reduce(concatPaths=[],collect(pathFromRootNodes)| concatPaths+p)中的p作为所有路径
以reduce(distinctNodes=[],n在所有路径中|当n在distinctNodes中时,则distinctNodes,否则distinctNodes+n end)作为遍历顺序
返回[x在遍历顺序中| x.name]
我不会逐行解释,但要点是:

  • 我们构建从根到每个叶节点的路径集
  • 对于每个路径,我们构造一个合成键,该键在每个节点处组合
    order
    属性,通过该键对路径进行排序,得到到达每个叶节点的顺序
    • 这可能是最重要的一位——我们填充了“order”属性,这样我们就可以在路径上使用词汇ASCII排序来生成遍历顺序
  • 我们展平排序路径列表,并消除其中的节点重复,以获得遍历顺序

展示更多数据模型。层次结构是如何表示的?例如,节点之间是否存在关系?此外,
顺序
属性的意义是什么?顺序是相同级别上节点的顺序。我添加了一个关系示例。这表示所有关系。希望这能澄清.不应
N2
N3