Performance 如何提高neo4j数据库的性能

Performance 如何提高neo4j数据库的性能,performance,database-design,graph,neo4j,Performance,Database Design,Graph,Neo4j,我们使用下面的查询创建了neo4j数据库。我们的csv文件包含50k行 // Query1 CREATE CONSTRAINT ON (p:PR) ASSERT p.prId IS UNIQUE; USING PERIODIC COMMIT LOAD CSV WITH HEADERS FROM 'file:///2015_PRData.csv' AS line WITH line, SPLIT(SPLIT(line.`Open Date`, ' ')[0], '/') AS opnDateLi

我们使用下面的查询创建了neo4j数据库。我们的csv文件包含50k行

// Query1
CREATE CONSTRAINT ON (p:PR) ASSERT p.prId IS UNIQUE;

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM
'file:///2015_PRData.csv' AS line WITH line,
SPLIT(SPLIT(line.`Open Date`, ' ')[0], '/') AS opnDateList,
SPLIT(SPLIT(line.`Closed Date`, ' ')[0], '/') AS clsDateList
MERGE (prNode:PR{prId:TOINT(line.prId)})
MERGE (app:Application{appName:line.Application})
MERGE (func:Function{funName:line.Function})
MERGE (subfunc:SubFunction{subFunName:line.Subfunction})
MERGE (cat:Category{catName:line.Category})
MERGE (rel:Release{relName:line.Release})
MERGE (custNode:Customer{customerName:line.`Server Name`})
MERGE (prOpenDate:PROpenDate{openDate:SPLIT(line.`Open Date`, ' ')[0]})
SET prOpenDate.day = TOINT(opnDateList[1]),prOpenDate.month = TOINT(opnDateList[0]),prOpenDate.year = opnDateList[2]
MERGE (prClosedDate:PRClosedDate{closedDate:SPLIT(line.`Closed Date`, ' ')[0]})
SET prClosedDate.day = TOINT(clsDateList[1]),prClosedDate.month = TOINT(clsDateList[0]),prClosedDate.year = clsDateList[2]
MERGE (app)-[:PART_OF_APPLN]->(func)
MERGE (func)-[:PART_OF_FUNCTION]->(subfunc)
MERGE (subfunc)-[:PART_OF_SUBFUNCTION]->(cat)
MERGE (prNode)-[:CATEGORY]->(cat)
MERGE (prNode)-[:REPORTED_BY]->(custNode)
MERGE (prNode)-[:OPEN_ON]->(prOpenDate)
MERGE (prNode)-[:CLOSED_ON]->(prClosedDate)
MERGE (prNode)-[:REPORTED_IN]->(rel)

Query 2:
//change year for open date nodes
MERGE (q:PROpenDate) SET q.year=SPLIT(q.year,' ')[0] return q;

Query 3:
//change year for closed date nodes
MERGE (q:PRClosedDate) SET q.year=SPLIT(q.year,' ')[0] return q;

Query 4:
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM
'file:///2015_PR_WithCP.csv' AS line WITH line
MERGE (cpNode:CP{cpId:line.cpId})
MERGE (prnode:PR{prId:TOINT(SPLIT(line.prRefId, 'PR')[1])})
CREATE (prnode)-[:FIXED_BY]->(cpNode)

Query 5:
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM
'file:///2015_CPWithFilename.csv' AS line WITH line
MERGE (cpNode:CP{cpId:line.cpId})
MERGE (cpFile:FILE{fileName:line.fileName})
CREATE (cpNode)-[:CONTAINS]->(cpFile)

Query 6:   
USING PERIODIC COMMIT 100
LOAD CSV WITH HEADERS FROM
'file:///2015_CPcomments.csv' AS line
MERGE (cpNode:CP{cpId:line.cpId})
MERGE (fileNode:FILE{fileName:line.fileName})
MERGE (owner:DougUser{userId:line.cpOwner})
MERGE (reviewer:DougUser{userId:line.cpReviewer})
MERGE (cpNode)-[:SUBMITTED_BY]->(owner)
WITH line WHERE line.reviewComment IS NOT NULL
MERGE (comment:ReviewComment{commentText:line.reviewComment,contextCP:line.cpId})
MERGE (comment)-[:GIVEN_BY]->(reviewer)
MERGE (comment)-[:COMMENT_FOR]->(fileNode)
在neo4j中上传数据需要更多的时间。首次查询超过7小时

另外,从服务器获取数据也需要更多的时间

MATCH (pr:PR)-[:FIXED_BY]-(cp) 
MATCH (cp)-[:CONTAINS]-(file)  
MATCH (pr)-[:CLOSED_ON]-(cls) 
MATCH (pr)-[:REPORTED_BY]-(custs) 
MATCH (pr)-[:CATEGORY]-(cats) 
WHERE  file.fileName STARTS WITH 'xyz'  AND NOT(cls.closedDate = '' )AND 
apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') >= apoc.date.parse('01/01/2014','s', 'MM/dd/yyyy') AND apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') <= apoc.date.parse('06/13/2017','s', 'MM/dd/yyyy') 
RETURN collect(DISTINCT custs.customerName) AS customers, collect(DISTINCT cats.catName) AS categories
MATCH(pr:pr)-[:FIXED_BY]-(cp)
匹配(cp)-[:包含]-(文件)
匹配(pr)-[:关闭]-(cls)
匹配(pr)-[:报告人](客户)
匹配(pr)-[:类别]-(猫)
其中file.fileName以“xyz”开头,而不是(cls.closedDate='')和

apoc.date.parse(cls.closedDate,'s','MM/dd/yyyyy')>=apoc.date.parse('01/01/2014','s','MM/dd/yyyyy')和apoc.date.parse(cls.closedDate,'s','MM/dd/yyyyy')执行每次合并时,您的主要问题可能是缺少索引/约束。合并类似于匹配或创建,如果要合并的标签/属性上没有索引,则db必须执行标签扫描,这意味着它必须检查数据库中该标签的每个节点,并访问它们的所有属性,以查找其中哪些具有所需的属性,这是非常昂贵的。添加节点时,标签扫描(以及合并)变得越来越慢。改用索引

在对具有多个属性的节点使用“合并”的情况下,如果存在唯一属性(例如id属性),请仅使用该属性进行合并,然后在“创建集”上使用以设置剩余的非唯一属性

您可以通过在查询之前使用EXPLAIN检查效率低下,这将在不执行查询的情况下生成查询计划。您希望确保看到NodeUniqueIndexSeek和NodeIndexSeek。如果看到NodeByLabelScan,则很可能需要通过在相关标签/属性上添加索引来优化查询

某些查询在应该使用MATCH时使用MERGE(查询2和查询3,以及后续查询中可能存在的某些节点,您知道该节点已经存在)。如果试图在数据库中查找现有节点,而不尝试添加节点,请改用“匹配”

查询6的WITH子句中存在缺陷,您还需要在WITH中包含
reviewer
fileNode
,否则这些变量将超出范围,并且不会绑定到您先前在查询中创建的节点

查询6在查询计划中也有一个Eager(由
所有者
审阅者
节点合并而成),这将阻止定期提交并导致查询运行效率低下。要解决此问题,请首先导入all:DougUser节点(此处使用单个变量),然后执行查询6(但对
owner
reviewer
都使用MATCH,因为它们应该存在于图中)


对于查询7,解释计划显示一个NodeByLabelScan,因此它将在寻找匹配模式的所有:PR节点上运行。最好将:FILE标签添加到
FILE
节点,这将改变以NodeIndexSeekByRange开始的计划,因此您的开始节点将是:以“xyz”开始的文件节点(通过快速索引查找),它将从中找到匹配模式。

您有哪些索引和约束?(
:浏览器中的schema
)您是否进行了一些neo4j配置?我正在试图了解您的缺点。但是我对这个neo4j非常陌生,如果您编辑我的一些查询,那将非常棒。第一个查询,即初始负载,是关于您在查询运行之前设置的约束/索引。在
:应用程序(appName)
:函数(funName)
:子函数(subFunName)
:类别(catName)
:发布(relName)
:客户(customerName)
:PROpenDate(openDate)
,和
:PRClosedDate(closedDate)
。您可能还希望为以后添加的一些其他节点(例如:CP、:FILE、:DougUser和:ReviewComment)创建索引/约束。此外,如果在查询之前添加
EXPLAIN
,则在没有索引查找的情况下,您将看到查询计划(并且查询将不会运行),您正在执行标签扫描,并且随着每个标签中的节点数目的增加,这些扫描变得越来越昂贵。如果我们假设为每行添加了唯一的节点,那么您将执行从1到50k的查找总和,即1250025000个标签扫描,乘以节点合并数(即8,因为:PR节点将至少使用唯一索引查找)。