C# 使用neo4jclient的性能问题
我目前正在为我所在行业的一些流程探索图形数据库的潜力。 一周前我开始使用Neo4Jclient,因此我低于标准初学者:-) 我对Neo4J非常兴奋,但我面临着巨大的性能问题,我需要帮助 我的项目的第一步是从现有文本文件填充Neo4j。 这些文件由使用简单模式格式化的行组成:C# 使用neo4jclient的性能问题,c#,neo4j,neo4jclient,C#,Neo4j,Neo4jclient,我目前正在为我所在行业的一些流程探索图形数据库的潜力。 一周前我开始使用Neo4Jclient,因此我低于标准初学者:-) 我对Neo4J非常兴奋,但我面临着巨大的性能问题,我需要帮助 我的项目的第一步是从现有文本文件填充Neo4j。 这些文件由使用简单模式格式化的行组成: StringID=StringLabel(String1,String2,...,StringN); 我考虑下面的行: #126=TYPE1(#80,#125); 我想创建一个标签为“TYPE1”的节点和两个属性: 1)
StringID=StringLabel(String1,String2,...,StringN);
<如果>我考虑下面的行:
#126=TYPE1(#80,#125);
我想创建一个标签为“TYPE1”的节点和两个属性:
1) 在上面的示例中,使用ObjectID:#126”的唯一ID
2) 包含将来使用的所有参数的字符串:上例中的“#80,#125”
我必须考虑我将处理多个前向引用,如下面的例子:
#153=TYPE22('0BTBFw6f90Nfh9rP1dl_3P',#144,#6289,$);
稍后将在文件中解析使用StringID“#6289”定义节点的行
因此,为了解决文件导入问题,我定义了以下类:
public class myEntity
{
public string propID { get; set; }
public string propATTR { get; set; }
public myEntity()
{
}
}
感谢我的文本文件中的转发引用(毫无疑问,我的Neo4J知识很差…)
我决定分三步工作:
第一个循环,我从文件中解析的每一行strLABEL、strID和strATTRIBUTES中提取,
然后,我使用以下代码为每行添加一个Neo4j节点:
strLabel = "(entity:" + strLABEL + " { propID: {newEntity}.propID })";
graphClient.Cypher
.Merge(strLabel)
.OnCreate()
.Set("entity = {newEntity}")
.WithParams(new {
newEntity = new {
propID = strID,
propATTR = strATTRIBUTES
}
})
.ExecuteWithoutResults();
var queryNode = graphClient.Cypher
.Match("(nodes)")
.Return(nodes => new {
NodeEntity = nodes.As<myEntity>(),
Labels = nodes.Labels()
}
);
graphClient.Cypher
.Match("(myEnt1)", "(myEnt2)")
.Where((myEntity myEnt1) => myEnt1.propID == strID)
.AndWhere((myEntity myEnt2) => myEnt2.propID == matchAttr)
.CreateUnique("myEnt1-[:INTOUCHWITH]->myEnt2")
.ExecuteWithoutResults();
然后,我使用以下代码匹配在Neo4J中创建的所有节点:
strLabel = "(entity:" + strLABEL + " { propID: {newEntity}.propID })";
graphClient.Cypher
.Merge(strLabel)
.OnCreate()
.Set("entity = {newEntity}")
.WithParams(new {
newEntity = new {
propID = strID,
propATTR = strATTRIBUTES
}
})
.ExecuteWithoutResults();
var queryNode = graphClient.Cypher
.Match("(nodes)")
.Return(nodes => new {
NodeEntity = nodes.As<myEntity>(),
Labels = nodes.Labels()
}
);
graphClient.Cypher
.Match("(myEnt1)", "(myEnt2)")
.Where((myEntity myEnt1) => myEnt1.propID == strID)
.AndWhere((myEntity myEnt2) => myEnt2.propID == matchAttr)
.CreateUnique("myEnt1-[:INTOUCHWITH]->myEnt2")
.ExecuteWithoutResults();
当我使用Cypher探索使用该代码填充的数据库时,得到的节点和关系是正确的,Neo4J的执行速度非常快,我测试过的任何查询都是如此。
这非常令人印象深刻,我相信Neo4j在我的行业中有巨大的潜力
但我今天的大问题是填充数据库所需的时间(我的配置:win8 x64、32Go RAM、SSD、intel core i7-3840QM 2.8GHz):
对于小型测试用例(6400行)
创建6373个节点需要13秒,创建7800个关系需要94秒
在真实的测试用例上(40000行)
创建38898个节点需要496秒,创建89532个关系需要3701秒(是的:一个多小时!)
毫无疑问,如此糟糕的性能是由我对neo4jclient缺乏了解直接造成的
如果社区能就如何解决这一瓶颈向我提供建议,那将对我大有帮助
提前谢谢你的帮助
致意
Max虽然我脑子里没有确切的语法可以为您记录下来,但我建议您在最初读取propATTR值时考虑将其拆分,并将其直接存储为Neo4j中的数组/集合。这将有望使您能够在Neo4j中批量创建关系,而不是在外部迭代节点并执行如此多的顺序事务 后一部分可能类似于:
MATCH (myEnt1),(myEnt2) WHERE myEnt1.propID IN myEnt2.propATTR
CREATE UNIQUE (myEnt1)-[:INTOUCHWITH]->(myEnt2)
抱歉,我的Cypher有点生疏,但重点是尝试将负载完全转移到Neo4j引擎,而不是应用程序逻辑和Neo4j服务器之间的连续往返。我建议,可能是这些往返影响了您的性能,而不是每个事务中涉及的单个工作,因此最大限度地减少事务的数量才是解决问题的方法。您多久导入一次数据?通常这是一次性的步骤(或很少的时间),而不是人们在考虑性能时通常关注的。如果你在3.7K秒内导入89K个关系,那不是快25/秒了吗?导入时每秒也会创建超过75个节点,对吗?真的那么慢吗?你真的需要经常重复这个过程吗?另一件事是,Neo4j有一个内置的导入器(使用CSV)。您是否尝试过使用它,而不是通过代码逐节点导入?顺便说一下:您的匹配码似乎没有使用标签过滤。首先,非常感谢您的回答。根据产品生命周期步骤的不同,导入数据可以是每天数次(设计阶段)或一次性步骤(操作阶段,移交后)。在当前代码中,我使用节点标签(可能有近200个不同的标签)对它们进行分类:这是一个好的选择还是应该为每个节点添加属性字符串类别?将尝试使用CSV导入并将结果通知您。最后,在导入阶段过滤期间,我没有使用标签,因为我需要匹配所有节点以在它们之间添加rel。