2016-12-24 140 views
2

我需要在Neo4j中创建一个二叉树。我已经开始创建两个CSV,一个用于顶点,一个用于边缘,然后我启动了两个查询来创建整个树。从CSV加载创建二叉树

我认为我可以创建只有一个查询整个树。 从我开始在CSV是这样的:

"parent","child_1","child_1_attr1","child_1_attr2","edge_1_attr1","edge_1_attr2","child_2","child_2_attr1","child_2_attr2","edge_2_attr1","edge_2_attr2" 
"vertex_1","vertex_2","2","5","4","1","vertex_3","5","3","2","2" 
"vertex_2","vertex_4","3","5","2","3","vertex_5","4","4","4","3" 
"vertex_3","vertex_6","2","1","2","4","vertex_7","2","2","5","5" 
"vertex_4","vertex_8","4","4","4","5","vertex_9","2","3","2","5" 
"vertex_5","vertex_10","1","1","3","3","vertex_11","1","3","2","3" 
"vertex_6","vertex_12","3","1","1","1","vertex_13","1","2","5","1" 
"vertex_7","vertex_14","4","2","2","1","vertex_15","2","5","4","3" 

然后我尝试此查询:

LOAD CSV WITH HEADERS FROM 'file:///Prova1.csv' AS line 
Match (p:Vertex {name: line.parent}) 
Create (c1:Vertex {name: line.child_1, attr1: line.child_1_attr1, attr2: line.child_1_attr2}) 
Create (c2:Vertex {name: line.child_2, attr1: line.child_2_attr1, attr2: line.child_2_attr2}) 
Create (p)<-[:EDGE {attr1: line.edge_1_attr1, attr2: line.edge_1_attr2}]-(c1) 
Create (p)<-[:EDGE {attr1: line.edge_2_attr1, attr2: line.edge_2_attr2}]-(c2) 

此查询我手动创建的第一个顶点之前,和我运行此查询,但只结果是我得到的是Vertices 1,2和3的创建。 它应该匹配父(始终已经创建),然后创建两个孩子,然后它应该将这两个孩子连接到他的父亲。

谁能帮帮我?

回答

1

对于每行/每行,可能您的执行视图执行所有的Cypher代码,然后重复执行下一行/行直到完成,这是不正确的。

相反,每一个人的Cypher操作将执行所有行,那么接下来的Cypher操作将所有行执行等

这意味着你的匹配操作:

Match (p:Vertex {name: line.parent})

执行跨越CSV中的所有行,然后才会进入下一个操作(您的CREATE,在所有行上执行),等等。

由于您声明手动创建了第一个顶点,该顶点是唯一可匹配的顶点,因此您的CSV中的所有其他行都将失败,因为CREATE语句尚未执行,因此这些节点不存在。这意味着只会创建两个顶点,它们的子节点完全匹配节点。

导入CSV数据首先创建所有节点,然后使用单独的CSV处理来匹配已创建的节点并创建相关关系时,这通常是一种很好的做法。然而,如果你确实想要在一个目标中创建所有东西,你可能会想在各个地方使用MERGE,但是如果你不完全理解MERGE的行为,这也是非常棘手的(这就像是一次尝试MATCH,如果找不到匹配,CREATE)或者不完全理解Cypher是如何执行的(如本例中那样)。

您还需要根据唯一节点值而不是所有属性合并,并设置其余属性。在相关标签/属性上使用唯一约束或索引(无论哪个都适合)以加快执行速度,特别是随着图形大小的增长,这也特别有用。

此查询可能有效。

LOAD CSV WITH HEADERS FROM 'file:///Prova1.csv' AS line 
MERGE (p:Vertex {name: line.parent}) 
MERGE (c1:Vertex {name: line.child_1}) 
SET c1.attr1 = line.child_1_attr1, c1.attr2 = line.child_1_attr2 
MERGE (c2:Vertex {name: line.child_2}) 
SET c2.attr1 = line.child_2_attr1, c2.attr2 = line.child_2_attr2 
Create (p)<-[:EDGE {attr1: line.edge_1_attr1, attr2: line.edge_1_attr2}]-(c1) 
Create (p)<-[:EDGE {attr1: line.edge_2_attr1, attr2: line.edge_2_attr2}]-(c2) 

这一个工程的原因是,到时候你第一次完成合并为你的图表的父节点,将已创建的所有父节点(或者更确切地说,节点,这将是父母)。

所以,当我们到达你的子节点的MERGE时,这将会匹配你图中已经创建的节点的大部分......在那个点上将创建的唯一新节点将是叶节点,由您的第一个MERGE创建,因为它们不会成为其他任何节点的父母,并且不会显示在您的CSV的父列中。

+0

首先,感谢对Cypher代码执行的详细解释,这是非常有用的,因为我正在通过我自己的Neo4j学习大学项目很难找到像这样简单的解释。 –

+0

顺便说一句,前几天我设法创建一个单一的查询树和像这样的小的,它的工作原理。事实是,我需要管理至少有2百万个节点的树,并且我正在考虑使用这种方法来改进创建带有2个CSV(一个用于节点,一个用于边)的2M节点树,在这种情况下需要300秒(在通用笔记本电脑上使用 '使用定期COMMIT')。 你认为用你的查询'使用周期性提交'会起作用吗?而且,你认为这个查询实际上可以缩短创建时间吗? –

+0

使用周期性COMMIT应该可以提高导入性能,并且您绝对需要一个唯一的约束:顶点(名称)(或者至少一个索引,如果名称不是唯一的顶点)。如果使用2个CSV,其中一个用于节点,另一个用于边缘,则可以在关系CSV中的顶点上自由使用MATCH而不是MERGE,并且可以在节点之间自行创建CREATE,这应该有助于提高性能。 – InverseFalcon

0

由于某种原因导入查询不起作用,因为您先匹配父项,然后创建节点和关系。我修改查询这样的,它现在的工作:所以

LOAD CSV WITH HEADERS FROM 'file:///test.csv' AS line 
CREATE (c1:Vertex {name: line.child_1, attr1: line.child_1_attr1, attr2: line.child_1_attr2}), 
     (c2:Vertex {name: line.child_2, attr1: line.child_2_attr1, attr2: line.child_2_attr2}) WITH c1,c2, line 
MATCH (p:Vertex {name:line.parent}) CREATE (p)<-[:EDGE {attr1: line.edge_1_attr1, attr2: line.edge_1_attr2}]-(c1), 
     (p)<-[:EDGE {attr1: line.edge_2_attr1, attr2: line.edge_2_attr2}]-(c2) 

如果先创建节点,然后匹配父和创建查询工作的关系。结果是这样的:

enter image description here

我将探讨您的查询找到一个理由,为什么它不工作,因为我真的不明白为什么它不工作。

+0

感谢您的帮助...这是我在失败后写的。解释为什么我的查询不起作用在下一个答案:) –

0
foreach (num in range(1,15) | 
merge (parent:Node {number: num}) 
merge (left:Node {number: num + num}) 
merge (right:Node {number: num + num + 1}) 
merge (left)<-[:LEFT]-(parent)-[:RIGHT]->(right) 
) 

说明: 这将创建一个完美的二叉树结构与31个节点。然后,您可以在CSV中包含相同的编号,以查找和添加属性到每个对应编号的节点。

在二叉树中,如果在值为1的第一个(根或最上方的节点)上包含数字属性,则将每个后续节点的数值增加1(从左到右;从上到下)方便的数学关系,其中每个节点的左边孩子的父母的数字+数字的数字值,右边的孩子是数字+数字+ 1.