0%

Neo4j 导入动态类型关系

今天在构建一批新的关系时,需要用 LOAD CSV 批量导入一些关系数据进去,但是这次的关系类型并不是固定的,而是在文件中指定的,CSV 文件格式如下:

1
2
3
4
5
6
7
8
9
10
AWI9o1sbC5n_pY7tOUdL|AWI96tqyetLN4cQh5GnC|EMERGENCY|紧急联络人
AWI85duqetLN4cQhYTVc|AWI-DASVC5n_pY7tH2i5|EMERGENCY|紧急联络人
AWI85duqetLN4cQhYTVc|AWI-DASVC5n_pY7tH2i5|RELATIVE|Spouse
AWI9-Vm7etLN4cQhC6gp|AWI9lGsNetLN4cQhK_8U|EMERGENCY|紧急联络人
AWI8pkY9etLN4cQhqdrQ|AWI8dIx9C5n_pY7tBKBJ|EMERGENCY|紧急联络人
AWI8pkY9etLN4cQhqdrQ|AWI8dIx9C5n_pY7tBKBJ|OTHER|Other
AWI-ZirYC5n_pY7tIn7b|AWI-d3TaC5n_pY7tUjVr|EMERGENCY|紧急联络人
AWI-ZirYC5n_pY7tIn7b|AWI-d3TaC5n_pY7tUjVr|RELATIVE|Cousin
AWI8UPZ3etLN4cQhsFoT|AWI9ngEwetLN4cQhS4hI|EMERGENCY|紧急联络人
AWI-CJ7jetLN4cQhNwgt|AWI-UkO6etLN4cQhDYhR|EMERGENCY|紧急联络人

第一列和第二列分别两个 Person 节点的 UUID,第三列是关系类型(type),第四列是关系的名称(name)。

我刚开始这样写的导入语句:

1
2
3
4
5
USING PERIODIC COMMIT 10000
LOAD CSV FROM 'file:////relation_all.csv' AS line FIELDTERMINATOR '|'
MATCH (p1:Person {uuid: line[0]})
MATCH (p2:Person {uuid: line[1]})
MERGE (p1)-[:line[2] {name: line[3]}]->(p2)

但是发现无法执行,由错误信息可知(下图所示),Neo4j 原始的 LOAD CSV 语句是不支持动态创建关系类型的。

我之前在介绍 Neo4j 冷启动预热缓存 时介绍过一个插件:APOC,这个插件功能非常强大,比如提供了很多好用的路径算法和强大的函数,之后有机会的话会慢慢介绍,今天介绍一下他的动态创建关系的函数 apoc.create.relationship,函数说明如下:

apoc.create.relationship(person1,'KNOWS',{key:value,…​}, person2) create relationship with dynamic rel-type

所以我的导入语句只需要改成:

1
2
3
4
5
6
7
USING PERIODIC COMMIT 10000
LOAD CSV FROM 'file:////relation_all.csv' AS line FIELDTERMINATOR '|'
MATCH (p1:Person {uuid: line[0]})
MATCH (p2:Person {uuid: line[1]})
WITH p1, p2, line
CALL apoc.create.relationship(p1, line[2], {name: line[3]}, p2) YIELD rel
RETURN rel

就完事大吉了。

但是考虑到这个 CSV 文件中的关系可能存在重复,所以我通过文档找到了另一个函数:

apoc.merge.relationship(startNode, relType, {key:value, …​}, {key:value, …​}, endNode) - merge relationship with dynamic type

这个函数中需要传两组 key-value,第一组是用来判断关系是否重复的,第二组是一些其他属性。

最终的导入语句如下:

1
2
3
4
5
6
7
USING PERIODIC COMMIT 10000
LOAD CSV FROM 'file:////relation_all.csv' AS line FIELDTERMINATOR '|'
MATCH (p1:Person {uuid: line[0]})
MATCH (p2:Person {uuid: line[1]})
WITH p1, p2, line
CALL apoc.merge.relationship(p1, line[2], {name: line[3]}, {}, p2) YIELD rel
RETURN rel