2017-11-30 1 views
3

다음 쿼리를 사용하여 neo4j 데이터베이스를 만들었습니다. Google CSV 파일에는 50,000 개의 행이 있습니다.neo4j 기본 데이터베이스의 성능을 향상시키는 방법

// 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 

위의 쿼리는 데이터를 가져 오는 데 5 분 이상 걸립니다. 이 문제를 해결하도록 도와주세요. 성능이 매우 나쁩니다.

+0

어떤 색인 및 제약 사항이 있습니까? (브라우저의': schema') neo4j 설정을 했습니까? – logisima

답변

2

각 병합을 수행 할 때 주요 문제는 색인/제약 조건이 부족할 수 있습니다. MERGE는 MATCH 또는 CREATE와 같으며, 머지중인 레이블/특성에 대한 색인이없는 경우 db는 레이블 스캔을 수행해야합니다. 즉, 레이블 스캔에서 레이블의 모든 단일 노드를 검사해야합니다. 데이터베이스에 액세스하고 모든 속성에 액세스하여 원하는 속성을 가진 객체 중 비용이 많이 드는 객체를 찾습니다. 노드를 추가하면 레이블 스캔 (따라서 병합)이 느려지고 느려집니다. 색인을 대신 사용하십시오.

여러 속성이있는 노드에서 MERGE를 사용하는 경우 고유 한 속성 (예 : id 속성)이있는 경우 해당 속성을 사용하는 MERGE가 ON CREATE SET을 사용하여 나머지 비 고유 속성.

쿼리 전에 EXPLAIN을 사용하면 비효율적인지 여부를 확인할 수 있으므로 쿼리를 실행하지 않고 쿼리 계획을 생성 할 수 있습니다. NodeUniqueIndexSeek 및 NodeIndexSeek가 표시되는지 확인하려고합니다. NodeByLabelScan이 표시되면 관련 레이블/등록 정보에 색인을 추가하여 쿼리를 최적화해야합니다.

일부 쿼리는 MATCH (쿼리 2와 3 및 노드가 이미 존재한다는 것을 알고있는 후속 쿼리 내의 일부 노드)를 사용해야 할 때 MERGE를 사용합니다. 데이터베이스에서 기존 노드를 찾고 노드를 추가하지 않으려는 경우 대신 MATCH를 사용하십시오.

쿼리 6에 WITH 절에 결함이있는 경우 reviewerfileNode을 WITH에 포함해야합니다. 그렇지 않으면이 변수가 범위를 벗어나서 이전에 쿼리에서 만든 노드에 바인딩되지 않습니다 .

쿼리 6도 정기적으로 커밋을 방지하고 비효율적으로 실행하는 쿼리를 발생합니다 (모두 ownerreviewer 노드의 병합에 의한) 쿼리 계획의 열망이있다. 이 문제를 해결하려면 먼저 DougUser 노드를 가져오고 (여기서 단일 변수를 사용) 쿼리 6을 실행합니다 (그러나 그래프에 존재해야하므로 ownerreviewer 모두에 MATCH를 사용합니다).

쿼리 7의 경우 EXPLAIN 계획에 NodeByLabelScan이 표시되므로 일치하는 패턴을 찾는 모든 PR 노드에서 실행됩니다. file 노드에 : FILE 레이블을 추가하는 것이 더 좋을 것입니다. 그러면 NodeIndexSeekByRange로 시작하도록 계획이 변경되므로 시작 노드는 다음과 같습니다. 'xyz'로 시작하는 FILE 노드 (빠른 색인 조회를 통해) 거기에서 일치하는 패턴.

+0

나는 당신의 터프를 이해하려고 노력하고 있습니다. 그러나 나는이 neo4j에 대해 아주 새로운데, 당신이 내 쿼리 중 일부를 편집하면 좋을 것입니다. – Swapnil

+1

첫 번째 쿼리 인 초기로드는 쿼리가 실행되기 전에 설정 한 제약 조건/인덱스에 대한 것입니다.': Application (appName)',': Function (funName)',': SubFunction (subFunName)',': 범주 (catName)',': 릴리스 (relName)',': 고객 (customerName)에 제약 조건이나 인덱스를 추가합니다.)','': PROpenDate (openDate)'',': PRClosedDate (closedDate)'를 포함한다. 나중에 추가 된 일부 노드 (예 : CP, : FILE, : DougUser 및 아마도 ReviewComment)에 대한 색인/제약 조건을 만들 수도 있습니다. 또한 쿼리 전에'EXPLAIN'을 추가하면 쿼리 계획이 표시됩니다 (쿼리가 실행되지 않습니다) – InverseFalcon

+1

인덱스 조회가 없으면 레이블 스캔을 수행하고 있으며 숫자가 점점 더 비싸집니다 이러한 각 레이블에있는 노드의 수가 증가합니다. 고유 한 노드가 각 행에 추가되었다고 가정하면 노드 병합의 수를 곱한 1250025000 개의 레이블 스캔 인 1에서 50k까지의 검색을 합산합니다 (PR 노드는 적어도 다음을 사용하기 때문에 8입니다. 고유 인덱스 조회). – InverseFalcon

관련 문제