Neo4J: превышен лимит накладных расходов GC при создании отношений

код:

load csv with headers from "https://data.cityofnewyork.us/api/views/feu5-w2e2/rows.csv?accessType=DOWNLOAD" as row
create (n:Contact) set n=row;

load csv with headers from "https://data.cityofnewyork.us/api/views/tesw-yqqr/rows.csv?accessType=DOWNLOAD" as row
create (n:Building) set n=row;

create index on :Contact(RegistrationID);

create index on :Building(RegistrationID);

Затем, когда я пытаюсь создать связь, она увеличивается до 8 ГБ оперативной памяти и в конечном итоге истекает, и приложение умирает, используя это:

MATCH (b:Building),(c:Contact)
where b.RegistrationID = c.RegistrationID
create (b)-[:CONTACTS_FOR]->(c)

Windows 7/64 бит i7-3770, 32 ГБ ОЗУ...


person ben    schedule 12.09.2016    source источник


Ответы (1)


Если ваш набор данных большой, вы не хотите выполнять какой-либо запрос, который работает со всей меткой, вы почти гарантированно увидите всплеск памяти, тайм-аут и, в конечном итоге, ошибку OutOfMemory в журналах neo4j. Порядок, в котором вы должны выполнять эти запросы, следующий:

1) Сделать индексы.

2) Объединить один из наборов данных и объединить отношения заранее вот так и использовать периодическую фиксацию, чтобы вам не приходилось хранить весь результат в памяти [EDIT: поскольку RegistrationID не является уникальным свойство, создайте для него резервный узел, чтобы часть ваших отношений могла быть предварительно построена]:

USING PERIODIC COMMIT 500
load csv with headers from "https://data.cityofnewyork.us/api/views/tesw-yqqr/rows.csv?accessType=DOWNLOAD" as row
CREATE (b:Building) SET b=row
MERGE (i:RegistrationID {RegistrationID: row.RegistrationID})
MERGE (b) - [:CONTACTS_FOR] -> (i)

3) Затем объедините другой набор данных. Ваш существующий индекс гарантирует, что если вы используете MERGE вместо CREATE, вы получите уже созданные узлы RegistrationID, которые вы вернули на последнем шаге:

USING PERIOD COMMIT 500
load csv with headers from "https://data.cityofnewyork.us/api/views/feu5-w2e2/rows.csv?accessType=DOWNLOAD" as row
CREATE (c:Contact) SET c = row
MERGE (i:RegistrationID {RegistrationID: row.RegistrationID})
MERGE (i) - [:CONTACT_FOR] -> (c)

Чтобы запросить контакты путем построения, используйте оператор * следующим образом:

MATCH (b:Building) WHERE <whatever conditions you want>
WITH b
MATCH (b) <- [:CONTACT_FOR*2] - (c)
RETURN c

Теперь, если ваши данные уже есть и вы не хотите перезагружать, вам придется использовать SKIP и LIMIT в своем запросе, чтобы обрабатывать только фрагмент за раз:

MATCH (b:Building)
WITH b
SKIP 0
LIMIT 500
MATCH (c:Contact) WHERE c._id = b._id
MERGE (b) - [:CONTACTS_FOR] -> (c)

а затем запустите его несколько раз, каждый раз перемещая SKIP и LIMIT вверх на 500.

Даже если ваша машина теоретически способна обрабатывать такой большой запрос, существуют ограничения, установленные как neo4j , так и JVM, на которой он работает, что может помешать вам использовать его. Попробуйте придумать решение, которое использует множество маленьких итерационных запросов вместо одного большого, обычно это намного эффективнее.

person Tore Eschliman    schedule 12.09.2016
comment
Это очень помогло и сработало очень быстро. Как мне также добавить слияние при второй загрузке для контактов для строк, которые имеют одинаковые значения в кортежах (FirstName, LastName) и (BusinessHouseNumber, BusinessStreetName, BusinessApartment, BusinessCity)? - person ben; 12.09.2016
comment
Это свяжет ваш (c:Contact) с другими (:Contact), имеющими такие же свойства: MERGE (d:Contact {FirstName: c.FirstName, LastName: c.LastName}) MERGE (c) - [:IS] -> (d) Вы это имели в виду? - person Tore Eschliman; 12.09.2016
comment
Что-то в этом роде, я думаю, что это сработает или, по крайней мере, направит меня на правильный путь, но проблема снова в памяти/производительности. Я начинаю думать, что мне нужно отказаться от neo4J, потому что это занимает слишком много времени и невероятно неэффективно для моих нужд памяти :( - person ben; 12.09.2016
comment
Поместите PERIODIC COMMIT 500 в верхней части второй загрузки, это я пропустил. neo4j очень производительный, но требует довольно активного управления памятью; если вы можете разбить свой запрос на шаги (используя PERIODIC COMMIT во время загрузки или SKIP...LIMIT во время других итерационных запросов), обязательно сделайте это, немного увеличенная стоимость транзакции легко покроется повышенной эффективностью. - person Tore Eschliman; 12.09.2016
comment
Я очень хочу построить следующие отношения: Здания имеют отношение один ко многим к контактам, присоединяйтесь к условию RegistrationID = RegistrationID. Затем контакты имеют отношение «многие к одному» обратно к зданиям с тем же условием соединения. Затем, наконец, контакты имеют отношение к другим контактам, где либо имя, либо фамилия совпадают, ИЛИ элементы почтового адреса одинаковы, ИЛИ оба из них. Есть ли способ построить это, не дожидаясь миллиарда лет? :) - person ben; 12.09.2016
comment
Я думаю, что это делает первую часть: используя периодическую фиксацию 500, загружайте csv с заголовками из data.cityofnewyork.us/api/views/feu5-w2e2/ как соответствие строки (b:Building {RegistrationID: row.RegistrationID}) соответствие (c:Contact {RegistrationID: row.RegistrationID}) объединить (c)-[:CONTACTS_OF]->(b) объединить (b)-[:CONTACT_FOR]->(c) - person ben; 12.09.2016
comment
Хорошо, это в основном там, я думаю. Мне все еще нужен способ ОБЪЕДИНЯТЬ контакты на основе совпадающих адресов. Могу ли я сделать это одновременно на втором этапе? Это будут совпадения (BusinessHouseNumber, BusinessStreetName, BusinessApartment, BusinessZip) - person ben; 12.09.2016