Neo4j 如何优化节点关系的创建?

Neo4j 如何优化节点关系的创建?,neo4j,neo4jclient,Neo4j,Neo4jclient,我已经创建了大约200000个节点。我想根据facebook好友列表建立他们之间的关系 首先,我得到父节点引用 var userquery = client.Cypher .Match("(n:User)") .Where("n.UserID=" + _ui.UserID) .Return<Node<UserInfo>>("n") .Results .Single(); var userquery=client.Cypher .M

我已经创建了大约200000个节点。我想根据facebook好友列表建立他们之间的关系

首先,我得到父节点引用

var userquery = client.Cypher
    .Match("(n:User)")
    .Where("n.UserID=" + _ui.UserID)
    .Return<Node<UserInfo>>("n")
    .Results
    .Single();
var userquery=client.Cypher
.Match(“(n:User)”)
.Where(“n.UserID=“+\u ui.UserID”)
.返回(“n”)
.结果
.Single();
然后根据facebook好友列表引用好友

var friendquery1 = client.Cypher
    .Match("(n:User)")
    .Where("n.ThirdPartyFriendsIds In[" + _ui.ThirdPartyFriendsIds + "]")
    .Return<Node<UserInfo>>("n");
var-friendquery1=client.Cypher
.Match(“(n:User)”)
.Where(“n.thirdpartyfriendsid In[”+_ui.thirdpartyfriendsid+“]))
.返回(“n”);
然后用我得到的参考建立关系

var friendquery = friendquery1.Results;

foreach(Node<UserInfo> friendnode in friendquery)
{
    client.CreateRelationship(userquery.Reference, new UserRelationship (friendnode.Reference));
}
var-friendquery=friendquery1.Results;
foreach(friendquery中的节点friendnode)
{
CreateRelationship(userquery.Reference,newuserrelationship(friendnode.Reference));
}

有人能帮我优化一下吗?建立关系需要相当长的时间

这里有很多地方可以改进

注射风险和参数 不要像这样在查询中编写代码:

.Where("n.UserID=" + _ui.UserID)
这对性能是不利的,因为它破坏了所有查询计划缓存,并且b)一个主要的安全漏洞正在等待发生。这叫做“注射”攻击。您可以在“SQL注入”中查找有关它的大量信息,但同样的风险也适用于Cypher。这也是对性能的影响

改为这样做:

.Where((User n) => n.UserID == _ui.UserID)
.Where("n.UserID = {userId}")
.WithParams(new { userId = _ui.UserID })
如果无法使用类似于这样的lambda表达式对其进行建模,则可以使用参数:

.Where((User n) => n.UserID == _ui.UserID)
.Where("n.UserID = {userId}")
.WithParams(new { userId = _ui.UserID })
节点引用 不要使用
节点
,如
节点>
。Neo4j 2.0不赞成使用原始节点ID的概念,并且随着时间的推移逐渐被淘汰。这有很多原因,还有很多其他关于它的文章,所以我不会在这里重复

如果需要数据,只需使用
UserInfo
。如果需要对该节点执行某些操作,请向Cypher查询添加更多子句

避免使用
IGraphClient.Cypher
以外的任何东西,如
IGraphClient.CreateRelationship
所有其他方法都使用Neo4j REST API,该API正逐渐被Cypher调用所取代

在这种情况下,性能问题是因为您正在为要创建的每个关系运行整个网络请求和DB事务。这很慢

相反,在一个密码查询中尽可能多地执行操作

把它们放在一起 让我们忽略C#,然后回到Cypher

查找用户:

MATCH (user:User)
WHERE user.UserID = {userId}
查找所有好友:

MATCH (friend:User)
WHERE friend.ThirdPartyFriendsId IN {thirdPartyFriendIds}
仅当关系不存在时才创建关系(这样您可以多次运行查询而不创建重复项):

现在让我们把所有这些放在一起:

MATCH (user:User)
WHERE user.UserID = {userId}
MATCH (friend:User)
WHERE friend.ThirdPartyFriendsId IN {thirdPartyFriendIds}
CREATE UNIQUE user-[:FRIENDS_WITH]->friend
现在我们把它转换成C#:

请注意,我们必须在最后调用
ExecuteWithoutResults
,因为我们不会返回任何结果。(我们不需要退回任何。)

免责声明:我刚刚在这里的回答窗口中直接输入了所有这些内容,因此可能会有一些小错误。不要复制和粘贴我的代码。遵循原则

更快 到目前为止,这种方法仍然需要为每个用户运行一次

MATCH (user:User)
MATCH (friend:User)
WHERE friend.ThirdPartyFriendId IN user.ThirdPartyFriendsIds
CREATE UNIQUE user-[:FRIENDS_WITH]->friend
类似这样的东西可以一次性创建所有用户之间的关系。(但可能需要很长时间,具体取决于您有多少用户。)

关键原则 告诉Neo4j你要做的全部事情,而不是小声地对它发出许多微小的命令。当它知道一大堆事情要做时,它会做得更好

永远不要通过将动态字符串值连接到查询中来构造查询。它不仅非常不安全,而且速度很慢,因为每次都要编译查询,而且代价很高


在你去C#之前,一定要从Cypher开始。您将获得更多帮助,因为任何使用Neo4j的人都可以提供帮助,而不仅仅是.NET人员。您将获得更好的结果,因为您将执行更多基于批处理的操作。

Tatham thnx对于您的回复,上述解决方案是可行的,但问题是一次性创建关系是抛出taskcanceled(超时)异常。如何增加超时时间。我的图形中有大约2lakh节点