我有大约80万个节点,我正在尝试使用Neo4j .Net客户端向Neo4j企业版插入大约800万个边缘。
我正在做这样的事情,这个过程真的很慢。尝试了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
}
}
答案 0 :(得分:0)
您正在使用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
}
}
请注意,我正在使用不带await
的ExecuteWithoutResultsAsync,以便异步处理这些组。