我有一个结构与此类似的csv文件。
elementID | groupID | sequence
abc | A | 0
dcv | A | 1
asd | B | 0
ccc | B | 1
abc | B | 2
和一个Neo4j图,其中已经创建了与elementID
和groupID
对应的节点并带有相应的ID。
现在从这个csv文件中,我想创建一个从每个group
(具有csv文件中指示的groupID
)到element
节点(具有{{1} }(在csv文件中指示),标签为elementID
,如果相应元组中的:STARTS
值为sequence
,标签为0
,如果 :STOPS
值是该组的最大值。
为清楚起见,请考虑以下关系上方的行:
sequence
我尝试与此建立(A)-[:STARTS]->(abc)
(A)-[:STOPS]->(dcv)
(B)-[:STARTS]->(asd)
(B)-[:STOPS]->(abc)
关系:
:START
但这似乎要永远做。
相反,为了建立其他类型的关系,我没有从哪里开始。
我该怎么办?
答案 0 :(得分:1)
您可以按行名访问行字段,因此不需要键上的UNWIND
:
LOAD CSV WITH HEADERS FROM "file:///file.csv" AS row
WITH row
WHERE toInteger(row.sequence) = 0
MATCH (t:Group {ID: row.groupID})
MATCH (b:Element {ID: row.elementID})
MERGE (t)-[:STARTS]->(b);
假设您在:Group(ID)
和:Element(ID)
上有索引,它应该相当快。
使用max
聚合来查找最大元素并创建关系,这将在单个查询中创建两个关系:
LOAD CSV WITH HEADERS FROM "file:/file.csv" as line
WITH line.groupID as groupID, collect({elementID: line.elementID, sequence:toInteger(line.sequence)}) as groupElements,max(toInteger(line.sequence)) as max
UNWIND groupElements as element
MATCH (g:Group {ID:groupID}),(e:Element {ID:element.elementID})
FOREACH(ignoreMe IN CASE WHEN element.sequence = 0 THEN [1] ELSE [] END | CREATE (g)-[:STARTS]->(e))
FOREACH(ignoreMe IN CASE WHEN element.sequence = max THEN [1] ELSE [] END | CREATE (g)-[:STOPS]->(e))
它使用的是此处描述的技巧:
https://markhneedham.com/blog/2014/08/22/neo4j-load-csv-handling-empty-columns/
更新:如果您有很多行的序列不是0和max,那么可以通过添加
过滤掉这些行WITH element,max,groupID
WHERE element.sequence = 0 OR element.sequence = max
在MATCH
之前,应避免对这些行进行索引查找。
更新FOREACH / CASE语法:这是针对Cypher在该领域缺乏功能的解决方法。
CASE expression是Cypher的if / then / else条件。但是,它是一个表达式(=返回值),并且不能包含写操作。这就是我们需要FOREACH的地方。
CASE WHEN element.sequence = 0 THEN [1] ELSE [] END
当序列等于0时返回包含数字1的数组。如果序列条件为true,则等效于此:
FOREACH(ignoreMe IN [1] | CREATE (g)-[:STARTS]->(e))
它将对数组中的每个元素执行|
之后的部分。由于未使用该变量,因此称为ignoreMe
。如果条件为假,则数组为空,因此将不执行CREATE语句。