我可以使用 1 个密码命令从 csv 文件加载节点和关系吗?
Can I load in nodes and relationships from a csv file using 1 cypher command?
我有 2 个 csv 文件,我试图使用 cypher 将其加载到 Neo4j 数据库中:drivers.csv 包含每个一级方程式赛车手和圈数 times.csv,它存储 F1 比赛中的每一圈。
我已经成功加载了所有的节点,虽然圈速文件很大所以花了很长时间!然后我尝试在之后添加关系,但是需要添加的太多以至于我放弃了等待(它花了好几天而且仍然没有完全加载)。
我很确定有一种方法可以同时加载节点和关系,这将允许我对我现在不能做的关系使用定期提交。本质上,我只需要将这 2 个命令合二为一,经过一些尝试后,我似乎无法弄清楚该怎么做?
// load in the lap_times.csv, changing the variable names - about half million nodes (takes 3-4 days)
PERIODIC COMMIT 25000
LOAD CSV WITH HEADERS from 'file:///lap_times.csv'
AS row
MERGE (lt: lapTimes {raceId: row.raceId, driverId: row.driverId, lap: row.lap, position: row.position, time: row.time, milliseconds: row.milliseconds})
RETURN lt;
// add a relationship between laptimes, drivers and races - takes 3-4 days
MATCH (lt:lapTimes),(d:Driver),(r:race)
WHERE lt.raceId = r.raceId AND lt.driverId = d.driverId
MERGE (d)-[rel8:LAPPING_AT]->(lt)
MERGE (r)-[rel9:TIMED_LAP]->(lt)
RETURN type(rel8), type(rel9)
在此先感谢您的帮助!
您应该在此处查看索引文档:
https://neo4j.com/docs/cypher-manual/current/administration/indexes-for-search-performance/
基本上,索引一旦创建,就可以针对给定 属性 或属性快速查找给定标签的节点。如果您没有索引并且对节点进行 MATCH 或 MERGE,那么对于该 MATCH 或 MERGE 的每一行,它必须对给定标签的所有节点进行标签扫描并检查它们的所有属性以找到节点,这变得非常昂贵,尤其是在加载 CSV 时,因为这些操作可能会发生 CSV 中的每一行。
对于你的 :lapTimes 节点(虽然我们建议你在大多数情况下使用单数标签),如果你的图表中有 none 个节点开始,那么 CREATE 而不是 MERGE 就可以了.您可能需要 :lapTimes(raceId, driverId, lap)
上的复合索引,因为它应该唯一标识节点,如果您需要稍后查找它。在这里使用 CREATE 而不是 MERGE 应该处理得更快。
您的第二个查询应该在 :lapTimes 节点上进行匹配(标签扫描),并且每个查询都在 :race 和 :driver 节点上进行索引查找,因此索引是性能的关键。
您需要索引::race(raceId)
和 :Driver(driverId)
。
MATCH (lt:lapTimes)
WITH lt, lt.raceId as raceId, lt.driverId as driverId
MATCH (d:Driver), (r:race)
WHERE r.raceId = raceId AND d.driverId = driverId
MERGE (d)-[:LAPPING_AT]->(lt)
MERGE (r)-[:TIMED_LAP]->(lt)
如果您知道没有重复的条目,您可能会考虑对关系使用 CREATE 而不是 MERGE。
我删除了你的 RETURN 因为返回的类型不是有用的信息。
此外,请考虑为您的节点标签使用一致的大小写,并且您在图表中的标签和您创建的索引之间使用相同的大小写。
此外,您可能希望批量处理这些更改,而不是尝试一次处理所有更改。
如果你安装了 APOC Procedures,你可以使用 apoc.periodic.iterate()
,它可以用于批量更改,这将更快更容易地处理你的堆。您仍然首先需要索引。
CALL apoc.periodic.iterate("
MATCH (lt:lapTimes)
WITH lt, lt.raceId as raceId, lt.driverId as driverId
MATCH (d:Driver), (r:race)
WHERE r.raceId = raceId AND d.driverId = driverId
RETURN lt, d, ir",
"MERGE (d)-[:LAPPING_AT]->(lt)
MERGE (r)-[:TIMED_LAP]->(lt)", {}) YIELD batches, total, errorMessages
RETURN batches, total, errorMessages
单个 CSV 加载
如果您想在单个 CSV 加载中同时处理所有内容,您可以这样做,但同样您首先需要索引。以下是您至少需要的东西:
CREATE INDEX ON :Driver(driverId);
CREATE INDEX ON :Race(raceId);
创建这些之后,假设您是从头开始,您可以使用它(我修复了标签的大小写并将它们设为单数:
USING PERIODIC COMMIT 25000
LOAD CSV WITH HEADERS from 'file:///lap_times.csv' AS row
MERGE (d:Driver {driverId:row.driverId})
MERGE (r:Race {raceId:row.raceId})
CREATE (lt:LapTime {raceId: row.raceId, driverId: row.driverId, lap: row.lap, position: row.position, time: row.time, milliseconds: row.milliseconds})
CREATE (d)-[:LAPPING_AT]->(lt)
CREATE (r)-[:TIMED_LAP]->(lt)
我有 2 个 csv 文件,我试图使用 cypher 将其加载到 Neo4j 数据库中:drivers.csv 包含每个一级方程式赛车手和圈数 times.csv,它存储 F1 比赛中的每一圈。
我已经成功加载了所有的节点,虽然圈速文件很大所以花了很长时间!然后我尝试在之后添加关系,但是需要添加的太多以至于我放弃了等待(它花了好几天而且仍然没有完全加载)。
我很确定有一种方法可以同时加载节点和关系,这将允许我对我现在不能做的关系使用定期提交。本质上,我只需要将这 2 个命令合二为一,经过一些尝试后,我似乎无法弄清楚该怎么做?
// load in the lap_times.csv, changing the variable names - about half million nodes (takes 3-4 days)
PERIODIC COMMIT 25000
LOAD CSV WITH HEADERS from 'file:///lap_times.csv'
AS row
MERGE (lt: lapTimes {raceId: row.raceId, driverId: row.driverId, lap: row.lap, position: row.position, time: row.time, milliseconds: row.milliseconds})
RETURN lt;
// add a relationship between laptimes, drivers and races - takes 3-4 days
MATCH (lt:lapTimes),(d:Driver),(r:race)
WHERE lt.raceId = r.raceId AND lt.driverId = d.driverId
MERGE (d)-[rel8:LAPPING_AT]->(lt)
MERGE (r)-[rel9:TIMED_LAP]->(lt)
RETURN type(rel8), type(rel9)
在此先感谢您的帮助!
您应该在此处查看索引文档: https://neo4j.com/docs/cypher-manual/current/administration/indexes-for-search-performance/
基本上,索引一旦创建,就可以针对给定 属性 或属性快速查找给定标签的节点。如果您没有索引并且对节点进行 MATCH 或 MERGE,那么对于该 MATCH 或 MERGE 的每一行,它必须对给定标签的所有节点进行标签扫描并检查它们的所有属性以找到节点,这变得非常昂贵,尤其是在加载 CSV 时,因为这些操作可能会发生 CSV 中的每一行。
对于你的 :lapTimes 节点(虽然我们建议你在大多数情况下使用单数标签),如果你的图表中有 none 个节点开始,那么 CREATE 而不是 MERGE 就可以了.您可能需要 :lapTimes(raceId, driverId, lap)
上的复合索引,因为它应该唯一标识节点,如果您需要稍后查找它。在这里使用 CREATE 而不是 MERGE 应该处理得更快。
您的第二个查询应该在 :lapTimes 节点上进行匹配(标签扫描),并且每个查询都在 :race 和 :driver 节点上进行索引查找,因此索引是性能的关键。
您需要索引::race(raceId)
和 :Driver(driverId)
。
MATCH (lt:lapTimes)
WITH lt, lt.raceId as raceId, lt.driverId as driverId
MATCH (d:Driver), (r:race)
WHERE r.raceId = raceId AND d.driverId = driverId
MERGE (d)-[:LAPPING_AT]->(lt)
MERGE (r)-[:TIMED_LAP]->(lt)
如果您知道没有重复的条目,您可能会考虑对关系使用 CREATE 而不是 MERGE。
我删除了你的 RETURN 因为返回的类型不是有用的信息。
此外,请考虑为您的节点标签使用一致的大小写,并且您在图表中的标签和您创建的索引之间使用相同的大小写。
此外,您可能希望批量处理这些更改,而不是尝试一次处理所有更改。
如果你安装了 APOC Procedures,你可以使用 apoc.periodic.iterate()
,它可以用于批量更改,这将更快更容易地处理你的堆。您仍然首先需要索引。
CALL apoc.periodic.iterate("
MATCH (lt:lapTimes)
WITH lt, lt.raceId as raceId, lt.driverId as driverId
MATCH (d:Driver), (r:race)
WHERE r.raceId = raceId AND d.driverId = driverId
RETURN lt, d, ir",
"MERGE (d)-[:LAPPING_AT]->(lt)
MERGE (r)-[:TIMED_LAP]->(lt)", {}) YIELD batches, total, errorMessages
RETURN batches, total, errorMessages
单个 CSV 加载
如果您想在单个 CSV 加载中同时处理所有内容,您可以这样做,但同样您首先需要索引。以下是您至少需要的东西:
CREATE INDEX ON :Driver(driverId);
CREATE INDEX ON :Race(raceId);
创建这些之后,假设您是从头开始,您可以使用它(我修复了标签的大小写并将它们设为单数:
USING PERIODIC COMMIT 25000
LOAD CSV WITH HEADERS from 'file:///lap_times.csv' AS row
MERGE (d:Driver {driverId:row.driverId})
MERGE (r:Race {raceId:row.raceId})
CREATE (lt:LapTime {raceId: row.raceId, driverId: row.driverId, lap: row.lap, position: row.position, time: row.time, milliseconds: row.milliseconds})
CREATE (d)-[:LAPPING_AT]->(lt)
CREATE (r)-[:TIMED_LAP]->(lt)