我想使用 Cypher 在 Neo4j 中创建一个八叉树结构。我想创建类似于下图的内容:
关于如何在不必“手动”创建每个节点和关系的情况下实现这一点的任何想法?
您可以通过创建根在 Cypher 中执行此操作:
CREATE (root:Root:Leaf);
然后根据需要重复查询添加一个级别(但在某些时候事务会变得太大):
MATCH (n:Leaf)
REMOVE n:Leaf
FOREACH (i IN range(0, 7) |
CREATE (n)-[:CONTAINS]->(:Node:Leaf {value: coalesce(n.value, "") + toString(i)}));
如果您事先知道树的高度,则可以使用 Cypher 生成树。为简单起见,我生成了二叉树(分支因子为 2)。
WITH 0 as root, range(1,2) AS branches
WITH root as root, branches AS l1s, branches AS l2s
UNWIND l1s AS l1
UNWIND l2s AS l2
MERGE (n0:TreeNode {name: root})
MERGE (n1:TreeNode {name: l1})
MERGE (n2:TreeNode {name: l1+"_"+l2})
MERGE (n0)-[:X]->(n1)
MERGE (n1)-[:X]->(n2)
这将产生以下树:
解释:对于 k 层的树,我们复制branches
变量 k-1 次,展开每个列表。这将创建一个笛卡尔积,从而产生叶节点。对于 k 级的(完整)二叉树,这会产生 2^(k-1) 个叶节点。(这也适用于具有 8^(k-1) 个级别的八叉树。)
我们将级别的数字与下划线结合起来,为每个级别创建唯一的变量名称。可以这样查询 id:
WITH 0 as root, range(1,2) AS branches
WITH root as root, branches AS l1s, branches AS l2s
UNWIND l1s AS l1
UNWIND l2s AS l2
RETURN root, l1, l1+"_"+l2
这导致:
╒════╤═══╤═════════╕
│root│l1 │l1+"_"+l2│
╞════╪═══╪═════════╡
│0 │1 │1_1 │
├────┼───┼─────────┤
│0 │1 │1_2 │
├────┼───┼─────────┤
│0 │2 │2_1 │
├────┼───┼─────────┤
│0 │2 │2_2 │
└────┴───┴─────────┘
现在我们要做的就是创建节点和关系,同时注意节点/边只创建一次。这是通过使用MERGE
. (MERGE
起初可能看起来很棘手,但有很好的解释。)
如果要添加其他级别,请按如下方式更新查询:
l3s
l3
MERGE (n3:TreeNode {name: l1+"_"+l2+"_"+l3})
MERGE (n2)-[:X]->(n3)
当然,您也可以使用数字作为节点。您需要为每个节点生成一个新的数字“id”,而不是附加下划线。
WITH range(1,2) AS branches
WITH branches AS l1s, branches AS l2s
UNWIND l1s AS l1
UNWIND l2s AS l2
MERGE (n0:TreeNode {number: 0})
MERGE (n1:TreeNode {number: l1})
MERGE (n2:TreeNode {number: 2*l1+l2})
MERGE (n0)-[:X]->(n1)
MERGE (n1)-[:X]->(n2)
结果:
我不确定 cypher 是否可以做到这一点,但您可以使用编程语言并连接到 neo4j 来创建节点和关系。
以 PHP 为例:
function create_children($parent){
print "\n$parent: ";
for ($i=0; $i<=7;$i++) {
$node_id = (int) "$parent"."$i";
$children[] = $node_id;
print "$node_id,";
// create children nodes
// CREATE (child:node) SET node_id = $node_id
//create relationship here
// MATCH (parent:node) where node_id = $parent
// CREATE (parent)-[r:parent_of]->(child)
}
return $children;
}
function create_tree ($root, $depth) {
if ($depth ==0) return;
else{
$children = create_children($root);
$depth--;
foreach ($children as $child) {
create_tree($child, $depth);
}
}
}
// MAIN
// CREATE (parent:node) SET node_id=0;
create_tree(0,3);
当然,密码语句在哪里,您需要连接到 neo4j 实例并执行这些语句。
如果您不确定如何执行此操作,您可以打印出密码语句,然后将它们粘贴到 neo shell 或浏览器
中,这是运行create_tree(0,2)
的输出输出显示父级后跟其八个子级
0: 00,01,02,03,04,05,06,07,
00: 00,01,02,03,04,05,06,07,
01: 10,11,12,13,14,15,16,17,
02: 20,21,22,23,24,25,26,27,
03: 30,31,32,33,34,35,36,37,
04: 40,41,42,43,44,45,46,47,
05: 50,51,52,53,54,55,56,57,
06: 60,61,62,63,64,65,66,67,
07: 70,71,72,73,74,75,76,77,
让我知道这是否是您要找的