2017-10-04 2 views
2

저는 Neo4j를 처음 접했고 기본에 대해 이해할 수없는 것이 있어야합니다.Neo4j, Cypher 명령으로 대량로드

Java에서 많은 객체를 가지고 있으며이를 사용하여 Java 드라이버와 Cypher를 사용하여 Neo4j 그래프를 채 웁니다. 내 코드는 다음과 같이 작동합니다

// nodes 
for (Person person: persons) 
    session.run (String.format ( 
    "CREATE (:Person { id: '%s', name: \"%s\", surname: \"%s\" })", 
    person.getId(), person.getName(), person.getSurname() 
)); 

// relations 
session.run ("CREATE INDEX ON :Person(id)"); 

for (Friendship friendship: friendships) 
    session.run (String.format ( 
    "MATCH (from:Person { id: '%s' }), (to:Person { id: '%s' })\n" + 
    "CREATE (from)-:KNOWS->(to)\n", 
    friendship.getFrom().getId(), 
    friendship.getTo().getId() 
)); 

(나는 다스 노드 유형을 가지고 관계 유형의 같은 수에 대한 원인, 실제로는 약간 더 복잡).

이제는 300k 노드와 1M 관계를로드하는 데 1 시간 이상 걸리는 것과 같이 매우 느립니다 (Neo4j가 12/16GB RAM을 사용하는 상당히 빠른 MacBookPro에서).

내가 잘못하고 있습니까? 대신 batch inserter을 사용해야합니까? (네트워크를 통해 graphDB에 액세스 할 수 있어야합니다.) 하나의 트랜잭션에 더 많은 삽입을 그룹화하여 무언가를 얻을 수 있습니까? (문서에서 볼 때, 트랜잭션은 롤백 및 격리 요구에만 유용합니다.

답변

0

저는 Python으로 Neo4j에서 왔습니다. 그러나 여기에서 문제는 Cypher 명령과 관련이 있다고 생각합니다. 두 가지 제안이 있습니다.

가장자리를 개별적으로 일치시키는 것이 더 빠릅니다. 내 기본 벤치 마크에 나는이와 24ms 대 15ms의 차이 볼 (편집 :이 벤치 마크는 반신 반의) :

MATCH (from:Person { id: '%s' }) 
MATCH (to:Person { id: '%s' }) 
CREATE (from)-:KNOWS->(to) 

또 다른 옵션은 긴장을 풀을 사용하는 것입니다. BOLT 인터페이스와 함께 사용하면 배치 인서 터를 사용하지 않고도 트랜잭션을 더 적게 보낼 수 있습니다. Python 구현을 용서하겠습니다. 여기서 복사하고 있기 때문에 Javascript Neo4j Driver 문서를 사용하여 변환 할 수 있습니다.

payload = {"list":[{"a":"Name1","b":"Name2"},{"a":"Name3","b":"Name4"}]} 

statement = "UNWIND {list} AS d " 
statement += "MATCH (A:Person {name: d.a}) " 
statement += "MATCH (B:Person {name: d.b}) " 
statement += "MERGE (A)-[:KNOWS]-(B) " 

tx = session.begin_transaction() 
tx.run(statement,payload) 
tx.commit() 
+0

감사합니다.하지만 내 경우에는 효과가 없을 것이라고 생각합니다. Neo4j가 동일한 작업을 수행하는 동안 내 응용 프로그램이 내부 그래프 (해시 맵 사용)를 3 분 이내에 채우는 것을 고려할 때 24-15ms는 많이 다릅니다. 그건 옳지 않을 수도 있고, 다소 차이가있을 것입니다. WIND의 경우 매개 변수로 목록을 보내는 것이 결국 많은 노드와 가장자리가있는 것을 고려하면 결국 너무 큰 쿼리가 될 것이라고 생각합니다. – zakmck

+0

내 벤치 마크 결과가 나쁠 수도 있지만 최소한 UNWIND를 시도해 보길 강력히 권합니다. 페이로드 목록이 모든 데이터 * 일 필요는 없지만 위의 예제 코드에서와 같이 실제로는 그렇게합니다. 페이로드 크기가 ~ 100k이고 N 트랜잭션으로 가장자리를 채울 수 있다면 N * 100k 개별 트랜잭션에 비해 시간이 많이 절약됩니다. – sjc

+0

감사합니다 @sjc, 나는 UNWIND에 요점을보고, 나는 그것을 시도합니다. – zakmck

0

나는 이것에 관한 나의 경험을보고하는 것이 가치 있다고 생각한다.

나는 @sjc 제안을 따르고 UNWIND로 시도했다. 그러나 Cypher는 매개 변수화 된 노드 레이블 또는 관계 유형을 허용하지 않으므로 (그리고 레이블과 관계 유형이 12 개) 간단하지 않습니다. 하지만 결국 모든 가능한 유형을 반복 할 수 있었고 각 UNWIND 청크에 충분한 항목 (약 1000 개)을 보낼 수있었습니다.

UNWIND를 사용하는 코드는 훨씬 빠르지 만 충분히 빠르지는 않습니다. 제 의견에는 괜찮은 PC와 몇 백만 개의 노드, 수 억 개의 노드 이상에서는 좋지 않습니다.

삽입 장치 구성 요소는 HTTP 액세스를 중단해야하지만 Lucene 5.4에 대한 종속성으로 인해 많은 어려움을 겪었지만 훨씬 빠릅니다 (1-200 만 개의 노드를 업로드하는 데 몇 초가 걸립니다). Lucene 6을 사용하는 응용 프로그램 (데이터 생성) 내에서 사용하려면 클래스 패스에서 5.4와 6을 단순히 바꾸려고 시도했을 때 끔찍한 일이 발생했습니다. 나는 그 주위에 there is some mechanism to make this possible,하지만 쉽게 보이지 않는 확실히 잘 문서화되지 않습니다.

이러한 기본 작업을 효율적으로 실행하기 위해 이러한 모든 문제가 예상되지 않았습니다.