Создание отношений в графе Neo4j на основе значений столбцов max и min группы - PullRequest
1 голос
/ 05 июня 2019

У меня есть CSV-файл со структурой, подобной этой.

 elementID | groupID | sequence
     abc   |    A    |    0
     dcv   |    A    |    1
     asd   |    B    |    0
     ccc   |    B    |    1
     abc   |    B    |    2

и граф Neo4j, где узлы, соответствующие elementID и groupID, уже созданы с соответствующими идентификаторами.

Теперь из этого CSV-файла я хочу создать отношение для каждого group (с указанием groupID в файле CSV) к узлу element (с указанием elementID в CSV-файле).с меткой :STARTS , если значение sequence в соответствующем кортеже равно 0, с меткой :STOPS , если значение sequence является максимальным для этой группы.

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

(A)-[:STARTS]->(abc)
(A)-[:STOPS]->(dcv)
(B)-[:STARTS]->(asd)
(B)-[:STOPS]->(abc)

Я попытался создать отношение :START с этим:

LOAD CSV WITH HEADERS FROM "file:///file.csv" AS row
UNWIND KEYS(row) AS bid
WITH bid, row
WHERE bid="equence" AND TOINTEGER(row[bid]) = 0
MATCH (t:Group {Id: row.groupID})
MATCH (b:Element {Id: row.elementID})
WITH b, t
MERGE (t)-[:STARTS]->(b);

но кажется, что это навсегда.

Наоборот, я не знаю, с чего начать, чтобы создать другой тип отношений.

Как я могу это сделать?

1 Ответ

1 голос
/ 05 июня 2019

Вы можете получить доступ к полю строки по их имени, поэтому вам не нужны клавиши UNWIND on:

LOAD CSV WITH HEADERS FROM "file:///file.csv" AS row
WITH row
WHERE toInteger(row.sequence) = 0
MATCH (t:Group {ID: row.groupID})
MATCH (b:Element {ID: row.elementID})
MERGE (t)-[:STARTS]->(b);

Предположим, у вас есть индексы на :Group(ID) и :Element(ID).Быть достаточно быстрым.

Используйте max агрегацию, чтобы найти максимальный элемент и создать связь, это создает обе связи в одном запросе:

LOAD CSV WITH HEADERS FROM "file:/file.csv" as line
WITH line.groupID as groupID, collect({elementID: line.elementID, sequence:toInteger(line.sequence)}) as groupElements,max(toInteger(line.sequence)) as max
UNWIND groupElements as element
MATCH (g:Group {ID:groupID}),(e:Element {ID:element.elementID})
FOREACH(ignoreMe IN CASE WHEN element.sequence = 0 THEN [1] ELSE [] END | CREATE (g)-[:STARTS]->(e))
FOREACH(ignoreMe IN CASE WHEN element.sequence = max THEN [1] ELSE [] END | CREATE (g)-[:STOPS]->(e))

Используется описанный здесь трюк:

https://markhneedham.com/blog/2014/08/22/neo4j-load-csv-handling-empty-columns/

Обновление: Если у вас много строк с последовательностью, отличной от 0 и макс., Вы можете отфильтровать их, добавив

WITH element,max,groupID
WHERE element.sequence = 0 OR element.sequence = max

непосредственно перед MATCH, что должно исключить поиск индекса для этих строк.

Обновление синтаксиса FOREACH / CASE : это обходной путь для недостатка возможностей Cypher в этомarea.

Выражение CASE - это условие Cypher if / then / else.Однако это выражение (= возвращает значение) и не может содержать операции записи.Вот для чего нам нужно FOREACH .

CASE WHEN element.sequence = 0 THEN [1] ELSE [] END

Возвращает массив, содержащий число 1, когда последовательность равна 0. Если условие последовательности истинно, оно будет эквивалентно этому:

FOREACH(ignoreMe IN [1] | CREATE (g)-[:STARTS]->(e))

Он выполнит часть после | для каждого элемента в массиве.Переменная называется ignoreMe, потому что она не используется.Если условие ложно, массив пуст, поэтому оператор CREATE выполняться не будет.

...