使用 NodeJS,我将这些数据收集到 Neo4J:
- 用户(ID,登录名)
- 应用(ID、标题)
- 机器(ID、地址)
这完全是异步的。这意味着很多时候我可以获取有关数据库中尚不存在的用户和应用程序的信息。
因此,相反,只需创建项目,然后创建关系,我需要在用户和应用程序中为每一行运行合并以确保它们在数据库中。在此之后,我可以创建关系。
我正在发送到/cypher
端点。
params:{props:objects_array},
query:[
' FOREACH (p IN {props} | ',
' MERGE (u:user {id:p._user_id}) SET u.id = p._user_id ',
' MERGE (a:app {id:p._app_id}) SET a.id = p._app_id ',
' MERGE (m:machine {id:p._machine_id}) SET m.id = p._machine_id ',
' MERGE (u)-[:OPENED]->(a) ',
' MERGE (a)-[:USERS]->(u) ',
' MERGE (u)-[:WORK_IN]->(m) ',
' )',
].join("")
这正在工作,但太慢了。我通过更改并发请求和每个请求的行来控制平衡。
有 5 个并发请求和每个 500 行,它处理 4 个死锁错误,完成 5000 行需要 2 分钟。
问题是它始终需要 2 核 CPU 到 99%(数字海洋 4gb RAM),我需要将其扩展到 150 个并发请求,而不仅仅是 5 个。
我认为可能的解决方案是:
- 垂直扩展到四核(暂时解决,不是长期解决方案)
- 用于分发操作的数据库副本(这可能吗?
- 使用CREATE而不是MERGE的某种方法。 这非常快,但我需要确保唯一的 ID 和不同的属性。 也许使用约束?
- Neo4J真的能够处理这么多数据吗?
如果您只使用没有唯一约束或索引的 MERGE,则需要 Neo4j 对每个 MERGE 进行节点空间的完整扫描,以验证给定属性不存在其他项目。这意味着您最终会得到非常高的算法复杂性,并且还会受到磁盘限制。
您需要为在数据库中应该是唯一的标签/属性元组创建索引或(最好)唯一约束。这应该会显著加快您的 MERGE 查询速度。
此外,如果您使用新的事务终结点 (http://docs.neo4j.org/chunked/stable/rest-api-transactional.html),它将取代密码终结点,则会更好。它支持与密码端点相同的功能,但提高了性能,并提供了为每个HTTP调用运行多个密码语句的能力,并允许事务在服务器上保持运行,以便为客户端提供长时间运行的事务支持。
除此之外,Neo4j 2.1 将在未来几个月内发布,它包含多项性能增强功能,可显着加快并发查询执行速度。您可能想尝试即将到来的里程碑,看看这对您的表现有何帮助。
我不了解密码,但使用 neo4j REST API 您可以使用批量插入轻松实现这一点,您也可以在同一批处理操作中同时创建关系,在批处理中的后续作业中创建的节点。