Neo4j LOAD CSV Потоки приложений заблокированы

Я пытаюсь импортировать около 500000 строк данных из файла CSV, используя LOAD CSV команда в neo4j.

Данные в CSV организованы так:

Artists    |    Feature1    |    Feature2    |    Feature3

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

Для каждого артиста я хочу отслеживать, кого они показывают и кого они показывают. Каждый ряд CSV представляет песню. Для каждой песни, которую делает исполнитель (каждая строка CSV), я хотел бы добавить FEATURES Отношения с художником в Artist колонка художника в Features1/2/3 колонны.

Вот код, который я использую:

CREATE CONSTRAINT ON (a:Artist) ASSERT a.artistName IS UNIQUE;

USING PERIODIC COMMIT 50
LOAD CSV WITH HEADERS from 'https://aws.bigfile.csv' as line
MERGE (artist:Artist {artistName: line.Artist})
MERGE (feature1:Artist {artistName: line.Feature1})
MERGE (feature2:Artist {artistName: line.Feature2})
MERGE (feature3:Artist {artistName: line.Feature3})

MERGE (artist)-[f1:FEATURES]->(feature1) 
ON CREATE SET f1.strength = 1
ON MATCH SET f1.strength = f1.strength + 1

MERGE (artist)-[f2:FEATURES]->(feature2) 
ON CREATE SET f2.strength = 1
ON MATCH SET f2.strength = f2.strength + 1

MERGE (artist)-[f3:FEATURES]->(feature3) 
ON CREATE SET f3.strength = 1
ON MATCH SET f3.strength = f3.strength + 1

Желаемое поведение: первое появление кого-либо с участием другого художника создает FEATURES отношения и должны установить strength собственность FEATURES отношение равно 1. Для каждого последующего вхождения свойство прочности возрастает на 1. Поэтому художник А, который часто показывает художника В, должен иметь отношения, подобные (a)-[:FEATURES {strength: AHighNumber]->(b)

В этом случае отношения являются направленными, и вопросы направления (A с B отличается от B с A).

Должно быть более 10 000 разных исполнителей и, следовательно, узлов, но около 2000 узлов, у меня начинают появляться проблемы с системным таймаутом.

Я получаю кучу следующих сообщений в журналах:

2017-12-30 10:54:04.268+0000 WARN [o.n.k.i.c.MonitorGc] GC Monitor: Application threads blocked for 467ms.

Есть ли другая информация, которая может быть полезна при определении проблемы? Любая идея, как я мог бы реструктурировать свой код, чтобы избежать этой проблемы? Вся помощь очень ценится. Спасибо!

2 ответа

Решение

Если вы вставите запрос (не запускайте его, просто вставьте его) в браузер, вы получите предупреждение, которое, когда оно израсходовано, гласит:

План выполнения для этого запроса содержит оператор Eager, который заставляет все зависимые данные материализоваться в основной памяти перед продолжением. Использование LOAD CSV с большим набором данных в запросе, где план выполнения содержит оператор Eager, может потенциально потреблять много памяти и, вероятно, не будет работать должным образом. Для получения дополнительной информации и подсказок о том, как можно избежать проблем, обратитесь к разделу "Руководство по Neo4j" оператора Eager.

Это объясняет, почему вы видите проблемы с производительностью... это фактически исключает любое использование периодической фиксации.

Вы можете получить активные операции в плане запроса, если у вас есть несколько MERGE на одной метке узла. Общий подход к решению этой проблемы состоит в том, чтобы провести проход, объединяющий только узлы из одной переменной в CSV:

USING PERIODIC COMMIT 50
LOAD CSV WITH HEADERS from 'https://aws.bigfile.csv' as line
MERGE (artist:Artist {artistName: line.Artist})

Если line.Artist в вашем CSV есть все возможные исполнители, тогда один проход должен работать. Однако, если есть другие художники в line.Feature1 (и другие), которые не находятся в line.Artistзатем вам нужно будет сделать еще один проход для каждого из них по очереди, пока все ваши узлы не загрузятся (вы также можете нажать PERIODIC COMMIT до 5000 до 10000 или около того).

Обратите внимание, что ваши несколько MERGE с одинаковым типом связи для нескольких узлов также вносят вклад в операцию EAGER. Вы действительно должны посмотреть, сможете ли вы получить ваш CSV в другом формате. Вам не нужны все эти дополнительные столбцы, line.Artist а также line.Feature должно быть достаточно, и тогда у вас будет несколько рядов с одним и тем же исполнителем и другой функцией, и вы не будете увлечены энергичными операциями.

Ваша альтернатива, чтобы избежать активных операций и разрешить использование периодической фиксации, состоит в том, чтобы выполнить запрос (после того, как вы импортировали все ваши узлы) в 3 этапа:

USING PERIODIC COMMIT 10000
LOAD CSV WITH HEADERS from 'https://aws.bigfile.csv' as line
match (artist:Artist {artistName: line.Artist})
match (feature:Artist {artistName: line.Feature1})

MERGE (artist)-[f:FEATURES]->(feature1) 
ON CREATE SET f.strength = 1
ON MATCH SET f.strength = f.strength + 1

Затем повторите, но для line.Feature2 а также line.Feature3,

Я нашел (промежуточное) решение, которое напрямую не решает проблемы с памятью выше, но, тем не менее, работает.

Ранее я пытался создать узлы художников из исходного файла, объединяя их так, чтобы у каждого художника был один и только один узел. Я подозреваю, что создание / объединение узлов становилось дорогостоящим, поскольку для каждой строки шифра файлов по сути приходится просматривать все существующие узлы, чтобы определить, нужно ли создавать новый узел для этой строки.

Вместо этого я написал некоторый код Python, который получает уникальные значения (имена исполнителей) для каждого столбца, объединяет их в один длинный список и снова получает уникальные значения из этого списка, чтобы отфильтровать дубликаты исполнителей, которые появляются в нескольких столбцах. Затем я написал это в файл с одной колонкой художников. Я использовал этот намного более короткий файл для создания всех узлов художника. Код:

data = pd.read_csv('artists-full.csv', encoding = 'latin1')
columns = ['Artist', 'Feature1', 'Feature2', 'Feature3']
df = pd.DataFrame(data, columns=columns)

# Get an array of strings for each column. Clean out repeats
artists_set1 = df.loc[:, 'Artist'].unique().tolist()
artists_set2 = df.loc[:, 'Feature1'].unique().tolist()
artists_set3 = df.loc[:, 'Feature2'].unique().tolist()
artists_set4 = df.loc[:, 'Feature3'].unique().tolist()

# Combine the artists from different columns
artists_list = [artists_set1, artists_set2, artists_set3, artists_set4]
flat_artists_list = [item for sublist in artists_list for item in sublist]
# Get rid of duplicates by creating a set
artists_set = set(flat_artists_list)
# Turn the set back into a list
artists = list(artists_set)
print(len(artists))

# Write the list to csv
with open ('artists.csv', 'w', encoding='utf-8') as f:
    for artist in artists:
        f.write(str(artist) + '\n')

Оттуда я создал отношения между художниками, используя оригинальный файл и следующий код Cypher:

CREATE CONSTRAINT ON (a:Artist) ASSERT a.artistName IS UNIQUE;
MERGE (artist)-[f1:FEATURES]->(feature1) 
ON CREATE SET f1.strength = 1
ON MATCH SET f1.strength = f1.strength + 1

MERGE (artist)-[f2:FEATURES]->(feature2) 
ON CREATE SET f2.strength = 1
ON MATCH SET f2.strength = f2.strength + 1

MERGE (artist)-[f3:FEATURES]->(feature3) 
ON CREATE SET f3.strength = 1
ON MATCH SET f3.strength = f3.strength + 1
Другие вопросы по тегам