2017-11-30 11 views
3

以下のクエリを使用してneo4jデータベースを作成しました。私たちのcsvファイルには50k行が含まれています。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を実行する際にインデックス/制約がない可能性が高いことです。 MERGEはMATCHまたはCREATEと似ていますが、マージしているラベル/プロパティにインデックスがない場合、dbはラベルスキャンを実行する必要があります。つまり、ラベル内のそのラベルのすべてのノードをチェックする必要があります。それらのプロパティのすべてにアクセスして、あなたが望むプロパティを持っているものを探し出します。これは高価です。ノードを追加すると、ラベルスキャン(したがってMERGE)が遅くなり、遅くなります。索引を代わりに使用してください。

複数のプロパティを持つノードでMERGEを使用している場合、一意のプロパティ(idプロパティなど)がある場合、そのプロパティを使用するMERGEはON CREATE SETを使用して、プロパティ。

問合せの前にEXPLAINを使用すると、非効率をチェックできます。これにより、問合せを実行せずに問合せプランが生成されます。 NodeUniqueIndexSeekとNodeIndexSeekが表示されていることを確認する必要があります。 NodeByLabelScanが表示される場合は、該当するラベル/プロパティにインデックスを追加してクエリを最適化する必要があります。

クエリの中には、MATCH(クエリ2と3、おそらくノードが存在することがわかっている後続のクエリ内のいくつかのノード)を使用する必要がある場合にMERGEを使用します。データベース内の既存のノードを探してノードを追加しようとしない場合は、代わりにMATCHを使用します。

クエリー6にはWITH句に欠陥があります。また、reviewerfileNodeをWITHに含める必要があります。そうしないと、これらの変数はスコープ外になり、以前にクエリで作成したノードにバインドされません。

クエリー6には、クエリプランにEager(ownerとノードの両方のマージによる)が含まれているため、コミットが定期的に行われず、クエリが非効率的に実行されます。これを修正するには、DougUserノードを最初にインポートして(ここでは1つの変数を使用)、クエリ6のみを実行します(ただし、ownerreviewerの両方にMATCHを使用します)。

クエリ7では、EXPLAINプランにNodeByLabelScanが表示されるため、一致するパターンを探すすべてのPRノードで実行されます。 :FILEラベルをfileノードに追加すると、NodeIndexSeekByRangeで開始する計画が変更されるので、開始ノードは次のようになります。FILEノードが 'xyz'で始まる(高速インデックス参照)そこからの一致パターン。

+0

私はあなたのタフを理解しようとしています。しかし、私はこのneo4jをかなり新しくしています。あなたが私のクエリの一部を編集すると素晴らしいでしょう。 – Swapnil

+1

最初のクエリである初期ロードは、クエリが実行される前に設定した制約/インデックスに関するものです。':アプリケーション(appName) '、':Function(funName) '、':SubFunction(subFunName) '、':カテゴリー(catName) '、':リリース(relName) '、':Customer(customerName) ) '、':PROpenDate(openDate) '、':PRClosedDate(closedDate) 'と呼ばれます。後で追加する他のノード(CP、:FILE、:DougUser、おそらく:ReviewCommentなど)のインデックス/制約を作成することもできます。また、クエリの前に 'EXPLAIN'を追加すると、クエリプランが表示されます(クエリが実行されません) – InverseFalcon

+1

インデックスルックアップがないと、ラベルスキャンが実行されています。これらのラベルのそれぞれのノードの数が増加する。各行に一意のノードが追加されていると仮定すると、1250025000回のラベルスキャンでノードマージの数を掛けた合計が1から50kまでの合計を実行しています(PRノードは少なくともユニークなインデックスルックアップ)。 – InverseFalcon

関連する問題