Neo4j 在大数据集上的 MERGE 命令
Neo4j's MERGE command on big datasets
目前,我正在从事一个在网络分析领域实现Neo4j (V2.2.0) 数据库的项目。加载一些样本后,我试图加载一个大数据集(>1GB,>4M 行)。我面临的问题是,随着数据大小的增长,使用 MERGE 命令所花费的时间呈指数增长。当不是每一行都必须作为一个节点加载时,在线资源对于加载大数据集的最佳方法是什么是模棱两可的,我想对这个主题有所了解。强调一下,在这种情况下,我只是加载节点;关系是下一步。
基本上就三种方法
i) 为属性设置唯一性约束,并创建所有节点。这个方法主要是在引入MERGE命令之前使用的
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
其次是
USING PERIODIC COMMIT 250
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
CREATE (:Book{isbn=row.isbn, title=row.title, etc})
根据我的经验,如果发现重复项,这将 return 出错,从而停止查询。
ii) 合并节点及其所有属性。
USING PERIODIC COMMIT 250
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
MERGE (:Book{isbn=row.isbn, title=row.title, etc})
我曾尝试以这种方式加载我的设置,但在让该过程 运行 超过 36 小时并逐渐停止后,我认为应该有更好的选择,因为我的 ~200K最终加载了约 750K 个节点。
iii) 基于一个 属性 合并节点,然后设置其余节点。
USING PERIODIC COMMIT 250
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
MERGE (b:Book{isbn=row.isbn})
ON CREATE SET b.title = row.title
ON CREATE SET b.author = row.author
etc
我现在正在 运行 进行测试(约 20K 个节点)以查看从方法 ii 切换到 iii 是否会缩短执行时间,因为较小的样本给出了相互矛盾的结果。是否有我正在监督并可以缩短执行时间的方法?如果我没记错的话,批量插入器只适用于 CREATE 命令,而不适用于 MERGE 命令。
我已经允许 Neo4j 使用 4GB 内存,从我的任务管理器来看这已经足够了(只使用了超过 3GB)。
方法 iii) 应该是最快的解决方案,因为您 MERGE
对抗单个 属性。在执行 MERGE
之前是否创建了唯一性约束?如果没有索引(约束或普通索引),随着节点数量的增加,该过程将花费很长时间。
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
其次是:
USING PERIODIC COMMIT 20000
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
MERGE (b:Book{isbn=row.isbn})
ON CREATE SET b.title = row.title
ON CREATE SET b.author = row.author
这应该可行,您可以增加 PERIODIC COMMIT
。
这样我可以在几分钟内添加几十万个节点。
一般来说,请确保您有适当的索引。首先根据索引的属性合并节点(以利用快速查找),然后根据需要使用 SET
.
修改该节点的属性
除此之外,您的两种方法都通过事务层。如果您需要非常快速地将大量数据塞入数据库,您可能不想使用事务来执行此操作,因为它们为您提供了您可能不需要的功能,并且它们需要的开销会减慢您的速度。因此,更大的解决方案是不使用 LOAD CSV
插入数据,而是完全走另一条路线。
如果您使用的是 2.2 系列的 neo4j,您可以选择 batch inserter via java, or the neo4j-import tool 遗憾的是 2.2 之前不可用。它们的共同点是它们都不使用事务。
最后,无论哪种方式,您都应该阅读 Michael Hunger's article on importing data into neo4j,因为它提供了关于正在发生的事情的良好概念性讨论,以及如果您要将大量数据加载到其中,为什么需要跳过事务neo4j.
目前,我正在从事一个在网络分析领域实现Neo4j (V2.2.0) 数据库的项目。加载一些样本后,我试图加载一个大数据集(>1GB,>4M 行)。我面临的问题是,随着数据大小的增长,使用 MERGE 命令所花费的时间呈指数增长。当不是每一行都必须作为一个节点加载时,在线资源对于加载大数据集的最佳方法是什么是模棱两可的,我想对这个主题有所了解。强调一下,在这种情况下,我只是加载节点;关系是下一步。
基本上就三种方法
i) 为属性设置唯一性约束,并创建所有节点。这个方法主要是在引入MERGE命令之前使用的
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
其次是
USING PERIODIC COMMIT 250
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
CREATE (:Book{isbn=row.isbn, title=row.title, etc})
根据我的经验,如果发现重复项,这将 return 出错,从而停止查询。
ii) 合并节点及其所有属性。
USING PERIODIC COMMIT 250
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
MERGE (:Book{isbn=row.isbn, title=row.title, etc})
我曾尝试以这种方式加载我的设置,但在让该过程 运行 超过 36 小时并逐渐停止后,我认为应该有更好的选择,因为我的 ~200K最终加载了约 750K 个节点。
iii) 基于一个 属性 合并节点,然后设置其余节点。
USING PERIODIC COMMIT 250
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
MERGE (b:Book{isbn=row.isbn})
ON CREATE SET b.title = row.title
ON CREATE SET b.author = row.author
etc
我现在正在 运行 进行测试(约 20K 个节点)以查看从方法 ii 切换到 iii 是否会缩短执行时间,因为较小的样本给出了相互矛盾的结果。是否有我正在监督并可以缩短执行时间的方法?如果我没记错的话,批量插入器只适用于 CREATE 命令,而不适用于 MERGE 命令。
我已经允许 Neo4j 使用 4GB 内存,从我的任务管理器来看这已经足够了(只使用了超过 3GB)。
方法 iii) 应该是最快的解决方案,因为您 MERGE
对抗单个 属性。在执行 MERGE
之前是否创建了唯一性约束?如果没有索引(约束或普通索引),随着节点数量的增加,该过程将花费很长时间。
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
其次是:
USING PERIODIC COMMIT 20000
LOAD CSV WITH HEADERS FROM "file:C:\path\file.tsv" AS row FIELDTERMINATOR'\t'
MERGE (b:Book{isbn=row.isbn})
ON CREATE SET b.title = row.title
ON CREATE SET b.author = row.author
这应该可行,您可以增加 PERIODIC COMMIT
。
这样我可以在几分钟内添加几十万个节点。
一般来说,请确保您有适当的索引。首先根据索引的属性合并节点(以利用快速查找),然后根据需要使用 SET
.
除此之外,您的两种方法都通过事务层。如果您需要非常快速地将大量数据塞入数据库,您可能不想使用事务来执行此操作,因为它们为您提供了您可能不需要的功能,并且它们需要的开销会减慢您的速度。因此,更大的解决方案是不使用 LOAD CSV
插入数据,而是完全走另一条路线。
如果您使用的是 2.2 系列的 neo4j,您可以选择 batch inserter via java, or the neo4j-import tool 遗憾的是 2.2 之前不可用。它们的共同点是它们都不使用事务。
最后,无论哪种方式,您都应该阅读 Michael Hunger's article on importing data into neo4j,因为它提供了关于正在发生的事情的良好概念性讨论,以及如果您要将大量数据加载到其中,为什么需要跳过事务neo4j.