如果路径不存在,则创建所有不存在的节点和边

Create all nonexistent nodes and edges if path doesn't exist

提问人:user554481 提问时间:11/15/2023 最后编辑:user554481 更新时间:11/16/2023 访问量:43

问:

我想将 Python 包的模块表示为 neo4j 图中的节点。我得到如下输入,如果该模块尚未包含在内,则必须更新图形。假设我的输入如下所示:

a.b.c.d
a.b.c.e
a
a.b.c
a.b

如果已经存在,我不想在遇到 .我只想调用一个新节点并将其连接到 .同样,如果我得到并且这些节点都不存在,那么我想创建所有节点并相应地连接它们。我的实际输入可以为每个路径具有任意数量的节点,因此我想要一个可以处理任意路径长度的 Cypher 查询。a.b.ca.b.c.ddca.b.c

我是Cypher的新手。这是我的第一次尝试。

MERGE p=(module:Module {name: $module_name})
WITH p, module
MATCH (package:Module)-[:contains*]->(module)
WHERE [x in nodes(p) | x.name] = $module_path

但是,Cypher给了我以下错误:

查询不能以 MATCH 结尾

我也试过这个:

MERGE p=(:Module)-[:contains*]->(:Module)
WHERE [x in nodes(p) | x.name] = $module_path

但随后 Cypher 抱怨 .WHERE

请注意,我正在使用 neo4j Python 库来运行此查询,并传入如下参数: .如果有更好的方法,我很乐意以不同的方式参数化我的查询,但我不认为这是我错误的根源。{"module_path":["a","b","c"], "module_name":"c"}

我正在使用 neo4j ,社区版。5.12

Neo4J 密码

评论


答:

0赞 Christophe Willemsen 11/16/2023 #1

它可以通过以下查询(添加注释)来实现

// simulate your input
WITH "a.b.c.d" AS pkg 
// split on the dot, producing an array 
WITH split(pkg, ".") AS parts ['a','b','c','d']
// iterating of the array
UNWIND parts AS part 
// MERGE (match or create) the module with the name as id ( up to you which property to use )
MERGE (m:Module {id: part}) 
// break and introduce a variable being an array of the nodes created or matched
WITH collect(m) AS modules 
// use APOC to link those nodes together with the NEXT relationship
CALL apoc.nodes.link(modules,'NEXT') 

它产生这样的图形

enter image description here

稍后,如果您尝试对已经存在的模块路径执行相同的操作,它将不执行任何操作,例如,在上述操作之后,以下查询将不会创建任何内容

WITH "a.b.c" AS pkg
WITH split(pkg, ".") AS parts
UNWIND parts AS part
MERGE (m:Module {id: part})
WITH collect(m) AS modules
CALL apoc.nodes.link(modules,'NEXT')

enter image description here

评论

0赞 user554481 11/16/2023
当我逐字运行您的命令时,出现以下错误:“没有为此数据库实例注册名称的过程。请确保过程名称拼写正确,并且过程已正确部署。您运行的是哪个版本的 neo4j?我在 5.12 社区版上。apoc.nodes.link
0赞 Christophe Willemsen 11/16/2023
它假定您已启用 APOC neo4j.com/labs/apoc
1赞 Finbar Good 11/16/2023 #2

您可以使用纯 Cypher 方法,如下所示:

FOREACH (i IN range(0, size($module_path) - 2) | 
           MERGE (l:Module {name: $module_path[i]})
           MERGE (r:Module {name: $module_path[i+1]})          
           MERGE (l)-[:contains]->(r) );

您可以测试它如何与问题中的数据一起工作:

UNWIND [['a','b','c','d'],['a','b','c','e'],['a'],['a','b','c'],
        ['a','b']] AS modules
FOREACH (i IN range(0, size(modules) - 2) | 
            MERGE (l:Module {name: modules[i]})
            MERGE (r:Module {name: modules[i+1]})          
            MERGE (l)-[:contains]->(r) )

结果如下:enter image description here