当前位置: 首页 > 面试题库 >

使用REST优化Neo4j中的大批量批量插入

赫连华皓
2023-03-14
问题内容

我需要通过REST API的Batch端点将大量节点及其之间的关系插入到Neo4j中,大约每秒5k记录(仍在增加)。

这将是24x7连续插入。每条记录可能只需要创建一个节点,而其他记录可能需要两个节点并创建一个关系。

是否可以通过更改程序或修改Neo4j的设置来提高插入件的性能?

到目前为止,我的进度:

1.我已经使用Neo4j进行了一段时间的测试,但无法获得所需的性能

测试服务器盒:24核+ 32GB RAM

Neo4j 2.0.0-M06作为独立服务安装。

在同一台服务器上运行我的Java应用程序。(Neo4j和Java应用程序将来需要在自己的服务器上运行,因此无法使用嵌入式模式)

REST API端点:/ db / data / batch(目标:/ cypher)

使用模式索引,约束,合并,创建唯一。

2.我的架构:

neo4j-sh (0)$ schema
==> Indexes
==>   ON :REPLY(created_at)   ONLINE                             
==>   ON :REPLY(ids)          ONLINE (for uniqueness constraint) 
==>   ON :REPOST(created_at) ONLINE                             
==>   ON :REPOST(ids)        ONLINE (for uniqueness constraint) 
==>   ON :Post(userId)      ONLINE                             
==>   ON :Post(postId)    ONLINE (for uniqueness constraint) 
==> 
==> Constraints
==>   ON (post:Post) ASSERT post.postId IS UNIQUE
==>   ON (repost:REPOST) ASSERT repost.ids IS UNIQUE
==>   ON (reply:REPLY) ASSERT reply.ids IS UNIQUE

3.我的密码查询和JSON请求

3.1。 当一条记录需要创建单个节点时,作业说明如下所示

{"method" : "POST","to" : "/cypher","body" : {"query" : "MERGE (child:Post {postId:1001, userId:901})"}}

3.2。 当一条记录需要创建具有一种关系的两个节点时,作业说明如下所示

{"method" : "POST","to" : "/cypher","body" : {"query" : "MERGE (parent:Post {postId:1002, userId:902}) MERGE (child:Post {postId:1003, userId:903}) CREATE UNIQUE parent-[relationship:REPOST {ids:'1002_1003', created_at:'Wed Nov 06 14:06:56 AST 2013' }]->child"}}

3.3。 我通常每批发送100个工作描述(3.1和3.2混合使用),大约需要150〜250毫秒才能完成。

4.性能问题

4.1。 并发:

/ db / data / batch(目标:/
cypher)似乎不是线程安全的,已通过两个或多个并发线程进行了测试,这些线程使Neo4j服务器在数秒至数分钟内停机。

4.2。 具有约束的合并并不总是有效。

当使用单个查询创建两个节点和一个关系时(上面在3.2。中提到),它有时就像一个符咒;但是它有时会因CypherExecutionException而失败,并说节点xxxx之一已经存在,且标签为aaaa,属性为“
bbbbb” = [ccccc];根据我的理解,MERGE不是假定返回任何异常,而是返回已经存在的节点。

作为异常的结果,整个批次将失败并回滚,这会影响我的插入率。

我已经在GitHub上针对此问题打开了一个问题,https://github.com/neo4j/neo4j/issues/1428

4.3。 带有约束的CREATE UNIQUE不适用于创建关系。

这也在同一个github问题中提到。

4.4。 性能:

实际上,在将批处理与密码一起使用之前,我已经尝试过使用get_or_create(/ db / data / index / node /
Post?uniqueness = get_or_create&/ db / data / index / relationship /
XXXXX?uniqueness = get_or_create)进行旧索引编制

由于这些旧索引端点的性质(它们在索引中返回数据的位置,而不是实际数据存储中数据的位置),因此我不能在批处理中使用它们(需要引用同一批处理中先前创建的节点的功能)

我知道我可以启用auto_indexing,并直接处理数据存储而不是旧式索引,但是从2.0.0开始,他们提到架构索引优于旧式索引,因此我决定改用批处理+密码+模式索引方法

但是,使用批处理+密码时,我每秒只能获得约200个工作描述,如果带有约束的MERGE始终有效,则本来会更高,比如说约600〜800 / s,但仍远低于5k
/ s。我还尝试了模式索引,没有任何限制,就插入率而言,它甚至导致了更低的性能。


问题答案:

在2.0版本中,我将使用事务终结点批量创建语句,例如,每个http请求100或1000,每个事务大约30k-50k(直到您提交)。

有关新的流式交易端点的格式,请参见以下内容:

http://docs.neo4j.org/chunked/milestone/rest-api-
transactional.html

同样,为了获得如此高性能,连续的插入端点,我衷心建议编写一个可以在嵌入式API上运行并且可以轻松地每秒插入10k或更多节点和关系的服务器扩展,请参见此处的文档:

http://docs.neo4j.org/chunked/milestone/server-unmanaged-
extensions.html

对于纯插件,您不需要Cypher。对于并发,只需锁定一个众所周知的(要插入的每个子图)节点,这样就不会出现并发插入问题,您可以通过tx.acquireWriteLock()或从节点(REMOVE n.__lock__)删除不存在的属性来做到这一点。

有关编写非托管扩展(但使用cypher的扩展)的另一个示例,请签出该项目。它甚至具有一种可能对您有帮助的模式(将CSV文件发布到服务器端点以使用每行的cypher语句来执行)。

https://github.com/jexp/cypher-rs



 类似资料:
  • 问题内容: 我在将不同的缓冲区大小插入到本地SQLite DB中时发现,当缓冲区大小为10,000时,插入10,000,000行数据需要花费近8分钟的时间。换句话说,它需要1,000次写入来存储所有内容。 8分钟存储10,000,000个似乎太长了(或者是?) 可以优化以下任何一项以提高速度吗?请注意,插入的数据是字符的随机集合。 创建表格后,通过 是否可以进一步优化上述任何一项? 问题答案: 我

  • 为了提高性能,我想批量向Elasticsearch发送文档,而不是逐个发送。我在上读过弹性批量APIhttps://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-bulk.html 但是,我使用的是Elasticsearch rest客户端(https://www.elastic.co/guide/e

  • 我有一个用于将实时数据移动到测试环境中的事务数据置乱的过程。该表包含大约一亿行,分布在50个分区中。每月添加一个新分区。随着音量的增加,过程的执行速度比以前慢。 我正在考虑在我的代码中引入某种程度的并行化。这是一个新领域,我想知道是否有任何最佳实践。也许使用dbms_parallel_execute将更新拆分为块? 任何关于如何优化我的代码的建议都非常感谢! 编辑,我的解决方案基于以下反馈:重写部

  • 希望有人能帮助我。

  • 问题内容: 我读到这里:使用Python将CSV文件导入sqlite3数据库表 似乎每个人都建议使用逐行读取,而不是使用SQLite的bulk .import。但是,如果您有数百万行的数据,这将使插入速度非常慢。还有其他方法可以避免这种情况吗? 更新:我尝试下面的代码逐行插入,但是速度不如我预期的那样。反正有改进的地方吗 问题答案: 使用生成器表达式将您的数据即时划分为多个块,在事务内进行插入。这

  • 问题内容: 我试图切换一些硬编码的查询以使用参数化输入,但是遇到一个问题:如何格式化参数化批量插入的输入? 当前,代码如下所示: 一个可能的解决方案(从如何将数组插入到一个带有PHP和PDO的单个MySQL Prepared语句中 修改而来)似乎是: 有没有更好的方法来完成带有参数化查询的批量插入? 问题答案: 好吧,您有三个选择。 一次构建-执行多次。基本上,您只需为一行准备一次插入,然后循环执