2015-03-01 8 views
0

Я пытаюсь загрузить шаблоны данных в neo4j из cvs-файлов с использованием командных строк cypher. У меня есть два файла данных, один из которых содержит объекты, а другой - объекты.Проблемы с загрузкой шаблонов данных из CSV

файл объекта:

ID 
ABC-DE 
DEF 

Часть файла:

ID ParentID Level Size 
ABC ABC-DE 1 3 
DE ABC-DE 1 2 
AB ABC 2 2 
BC ABC 2 2 
DE DEF 1 2 
F DEF 2 1 
A AB 3 1 
B AB 3 1 
B BC 3 1 
C BC 3 1 
D DE 3 1 
E DE 3 1 

Cypher командные строки, используемые для загрузки данных:

LOAD CSV WITH HEADERS FROM 'file:///path_to_file/object.csv' as csvLine FIELDTERMINATOR '\t' CREATE (:Object { Name: csvLine.ID}) RETURN count(*); 
LOAD CSV WITH HEADERS FROM 'file:///path_to_file/part.csv' as csvLine FIELDTERMINATOR '\t' MATCH (o:Object {Name: csvLine.ParentID}) MERGE (p:Part {Name: csvLine.ID}) ON CREATE SET p.Size = csvLine.Size CREATE (o) -[:hasPart {Level: csvLine.Level}]-> (p) RETURN count(*); 
LOAD CSV WITH HEADERS FROM 'file:///path_to_file/part.csv' as csvLine FIELDTERMINATOR '\t' MATCH (o:Part {Name: csvLine.ParentID}) MERGE (p:Part {Name: csvLine.ID}) ON CREATE SET p.Size = csvLine.Size CREATE (o) -[:hasPart {Level: csvLine.Level}]-> (p) return count(*); 

Первые две командные строки выполнять должным образом, создавая 2 и 3 узла соответственно и соответствующие ссылки. Третья командная строка создает только 4 узла: AB, BC, D и E. По-видимому, создаются и связаны только узлы, связанные с существующими узлами.

Из содержимого файла CSV мы можем видеть, что родительские узлы перечислены перед дочерними узлами, поэтому мы могли ожидать, что узлы A, B и C могли быть созданы и соответственно связаны с AB и BC.

Является ли текущее поведение CSV загрузки ожидаемого, что предотвращает загрузку таких шаблонов или есть проблема в моем коде или ошибке?

Эта проблема существует как с neo4j 2.1.7, так и с neo4j 2.2.0-M04.

ответ

1

Итак, я думаю, что ваша проблема здесь в том, что cypher объединяет множество обновлений в одну транзакцию, а затем фиксирует их. Сколько он заключает транзакцию: configurable with USING PERIODIC COMMIT. Я мог ошибаться, но я думаю, что обычно это обрабатывает всю нагрузку данных как большую транзакцию.

Для вас это проблематично, потому что, когда вы находитесь, скажем, в строке №6, вам может потребоваться вернуться к узлу, который был бы создан в строке №3. За исключением того, что это не сработает; если транзакция еще не была выполнена, потому что cypher выполняет пакетную обработку результатов), то результат, не прошедший проверку, может быть недоступен для последующего выполнения запроса.

У вас есть несколько вариантов; нужно было бы сделать двухпроходный ИМПОРТ в этом файле детали. При первом проходе вы могли бы сделать это:

LOAD CSV WITH HEADERS FROM 'file:///path_to_file/part.csv' as csvLine FIELDTERMINATOR '\t' 
MERGE (p:Part {Name: csvLine.ID}) ON CREATE SET p.Size = csvLine.Size CREATE (o) -[:hasPart {Level: csvLine.Level}]-> (p) return count(*); 

(Это первая одна бы уверить все части существуют в БД)

Затем на втором проходе вы могли бы сделать это:

LOAD CSV WITH HEADERS FROM 'file:///path_to_file/part.csv' as csvLine FIELDTERMINATOR '\t' MATCH (o:Part {Name: csvLine.ParentID}) MATCH (p:Part {Name: csvLine.ID}) CREATE (o) -[:hasPart {Level: csvLine.Level}]-> (p) return count(*); 

(Это просто свяжет их с отношениями)

Другим вариантом было бы сделать что-то вроде USING PERIODIC COMMIT 1, но я не думаю, что это была бы хорошая идея; есть накладные расходы на транзакцию, и это резко снизит загрузку ваших данных, если у вас будет достаточное количество данных.

EDIT Если бы я был вами, я бы сделал импорт из двух сторон. Кроме того, в целом неплохо полагаться на упорядочение записей в плоских файлах, подобных этому, они, как правило, беспорядочны. Наконец, если вы выполняете двухпроходный импорт в своем файле детали, обратите внимание, что вам вообще не нужен ваш объектный файл! Любой объект, который причастен, будет создан через файл детали, а объектный файл не добавляет никаких дополнительных свойств, кроме ссылок на часть.

+0

Действительно, это было мое чувство, спасибо за вашу помощь. COMMIT 1, вероятно, будет проблемой для загрузки большого объема, я все равно попробую. Я изменился на двухпроходный импорт. Вы говорите, что мне не нужен объектный файл, разве вы не думаете, что сопоставление 728 000 идентификаторов узлов для импорта только 100 000 узлов будет не слишком медленным? – Pierre

+0

Я на самом деле не эксперт в SQL-базах данных, но я думал, что транзакции сохранят содержимое базы данных до тех пор, пока не будет выполнен COMMIT, не мешая механизму работы INSERT. Таким образом, не следует ожидать загрузки, как описано выше, для работы независимо от частоты COMMIT? – Pierre

+0

Пьер, это разумный вопрос. Я думаю, что мне понадобится neo4j dev для взвешивания, но я понимаю, что узел, который является 'CREATE'd в транзакции, недоступен/технически не существует до тех пор, пока эта транзакция не будет выполнена. Я интерпретирую это как часть «атомарности» гарантии транзакций (http://neo4j.com/docs/stable/transactions.html) - поэтому, я думаю (и снова это нужно дважды проверить), что если вы СОЗДАТЬ узел в транзакции, он еще не существует внутри этой транзакции. Он существует только при совершении транзакции. – FrobberOfBits

Смежные вопросы