使用Neo4j .Net客户端时边缘创建速度太慢
我已经有大约800k个节点,并且我尝试使用Neo4j .Net客户端将约800万条边缘插入到Neo4j企业版中。使用Neo4j .Net客户端时边缘创建速度太慢
我正在做这样的事情,这个过程真的很慢。尝试过Neo4j的驱动程序,但速度也很慢。我也得到了名称字段索引。 任何人都可以请建议一种替代方法来更快地创建边缘?
public static async Task AddEdges(List<Edge> edgeTable, IGraphClient client)
{
try
{
foreach (var item in edgeTable)
{
await client.Cypher
.Match("(parentNode:MyNodeType)", "(childNode:MyNodeType)")
.Where((MyNodeType parentNode, MyNodeType childNode) => parentNode.Name == item.SourceName && childNode.Name==item.MemberName)
.Create("(childNode)-[:belongsTo]->(parentNode)")
.ExecuteWithoutResultsAsync();
}
}
catch (Exception ex)
{
//ex handling
}
}
您正在使用await
把每个异步请求(由于您使用的ExecuteWithoutResultsAsync
)进入同步请求。这意味着当前的http请求必须在发送下一个请求之前作出响应,即使您不关心响应。 (顺便说一下,为了达到同样的目的,你可以使用ExecuteWithoutResults
而不使用await
。)这种串行化应尽可能避免。但是,根据您的使用情况,并行执行时存在死锁的可能性(由于在创建新关系时写入端节点锁定)。
此外,您只在每个事务性请求中执行单个CREATE
操作。这意味着您正在制作800万个序列化的事务请求。自然,这会很慢。
一个允许一定程度的异步操作,同时避免死锁的解决方案将涉及分析数据(理想情况下,以编程方式)以创建与其他组没有重叠节点的边组。即使组内的边缘仍然需要同步处理,不同的组可以并行处理而不会发生死锁。
如果您可以在单个事务中对一个组内的N个边执行操作,那么您可以避免为该组创建N个同步事务请求的开销,并且也可以避免上述死锁。
使用UNWIND
子句,您可以对单个请求中的列表中的数据进行迭代操作。像下面的东西应该工作。注意,edgeTable
输入列表必须从一个单一的组包含的边缘上,如以上所讨论:
public static async Task AddEdges(List<Edge> edgeTable, IGraphClient client) {
try {
client.Cypher
.Unwind(edgeTable, "item")
.Match("(parentNode:MyNodeType)", "(childNode:MyNodeType)")
.Where((MyNodeType parentNode, MyNodeType childNode) => parentNode.Name == item.SourceName && childNode.Name==item.MemberName)
.Create("(childNode)-[:belongsTo]->(parentNode)")
.ExecuteWithoutResultsAsync();
} catch (Exception ex) {
//ex handling
}
}
注意,我使用ExecuteWithoutResultsAsync而不01,使得基团异步处理。
但有一点需要注意的是,你不想让neo4j服务器一次处理太多,以免内存耗尽。因此,如果任何组太大,或者同时处理了太多的组,则可能需要限制调用AddEdges的速率,和/或将大组分成更小的块,并确保这些块同时相对于彼此进行处理。
需要多长时间? (如果没有实际的时间,你有估计吗?) –