Недавно меня спросили, как обрабатывать «массив» значений внутри столбца в CSV-файле с помощью инструмента LOAD CSV Neo4j, и хотя я изначально думал, что это невозможно, поскольку каждая ячейка рассматривается как строка, Майкл показал мне способ работать вокруг этого, что я думал, было довольно опрятно.
Допустим, у нас есть файл CSV, представляющий людей и их друзей. Это может выглядеть так:
name,friends "Mark","Michael,Peter" "Michael","Peter,Kenny" "Kenny","Anders,Michael"
И мы хотим иметь следующие узлы:
- отметка
- Майкл
- Питер
- Kenny
- Андерс
И следующие отношения друзей:
- Марк -> Майкл
- Марк -> Питер
- Михаил -> Питер
- Майкл -> Кенни
- Кенни -> Андерс
- Кенни -> Майкл
Мы начнем с загрузки CSV-файла и возврата каждой строки:
$ load csv with headers from "file:/Users/markneedham/Desktop/friends.csv" AS row RETURN row; +------------------------------------------------+ | row | +------------------------------------------------+ | {name -> "Mark", friends -> "Michael,Peter"} | | {name -> "Michael", friends -> "Peter,Kenny"} | | {name -> "Kenny", friends -> "Anders,Michael"} | +------------------------------------------------+ 3 rows
Как и ожидалось, столбец ‘friends’ рассматривается как String, что означает, что мы можем использовать функцию split, чтобы получить массив людей, с которыми мы хотим дружить:
$ load csv with headers from "file:/Users/markneedham/Desktop/friends.csv" AS row RETURN row, split(row.friends, ",") AS friends; +-----------------------------------------------------------------------+ | row | friends | +-----------------------------------------------------------------------+ | {name -> "Mark", friends -> "Michael,Peter"} | ["Michael","Peter"] | | {name -> "Michael", friends -> "Peter,Kenny"} | ["Peter","Kenny"] | | {name -> "Kenny", friends -> "Anders,Michael"} | ["Anders","Michael"] | +-----------------------------------------------------------------------+ 3 rows
Теперь, когда мы получили их как массив, мы можем использовать UNWIND, чтобы получить пары друзей, которых мы хотим создать:
$ load csv with headers from "file:/Users/markneedham/Desktop/friends.csv" AS row WITH row, split(row.friends, ",") AS friends UNWIND friends AS friend RETURN row.name, friend; +-----------------------+ | row.name | friend | +-----------------------+ | "Mark" | "Michael" | | "Mark" | "Peter" | | "Michael" | "Peter" | | "Michael" | "Kenny" | | "Kenny" | "Anders" | | "Kenny" | "Michael" | +-----------------------+ 6 rows
А теперь мы представим несколько операторов MERGE для создания соответствующих узлов и отношений:
$ load csv with headers from "file:/Users/markneedham/Desktop/friends.csv" AS row WITH row, split(row.friends, ",") AS friends UNWIND friends AS friend MERGE (p1:Person {name: row.name}) MERGE (p2:Person {name: friend}) MERGE (p1)-[:FRIENDS_WITH]->(p2); +-------------------+ | No data returned. | +-------------------+ Nodes created: 5 Relationships created: 6 Properties set: 5 Labels added: 5 373 ms
А теперь, если мы запросим базу данных, чтобы вернуть все узлы + отношения …
$ match (p1:Person)-[r]->(p2) RETURN p1,r, p2; +------------------------------------------------------------------------+ | p1 | r | p2 | +------------------------------------------------------------------------+ | Node[0]{name:"Mark"} | :FRIENDS_WITH[0]{} | Node[1]{name:"Michael"} | | Node[0]{name:"Mark"} | :FRIENDS_WITH[1]{} | Node[2]{name:"Peter"} | | Node[1]{name:"Michael"} | :FRIENDS_WITH[2]{} | Node[2]{name:"Peter"} | | Node[1]{name:"Michael"} | :FRIENDS_WITH[3]{} | Node[3]{name:"Kenny"} | | Node[3]{name:"Kenny"} | :FRIENDS_WITH[4]{} | Node[4]{name:"Anders"} | | Node[3]{name:"Kenny"} | :FRIENDS_WITH[5]{} | Node[1]{name:"Michael"} | +------------------------------------------------------------------------+ 6 rows
… вы увидите, что у нас есть все.
Если вместо списка людей через запятую у нас есть буквенный массив в ячейке …
name,friends "Mark", "[Michael,Peter]" "Michael", "[Peter,Kenny]" "Kenny", "[Anders,Michael]"
… Нам нужно настроить часть запроса, которая извлекает наших друзей, чтобы убрать первый и последний символы:
$ load csv with headers from "file:/Users/markneedham/Desktop/friendsa.csv" AS row RETURN row, split(substring(row.friends, 1, length(row.friends) -2), ",") AS friends; +-------------------------------------------------------------------------+ | row | friends | +-------------------------------------------------------------------------+ | {name -> "Mark", friends -> "[Michael,Peter]"} | ["Michael","Peter"] | | {name -> "Michael", friends -> "[Peter,Kenny]"} | ["Peter","Kenny"] | | {name -> "Kenny", friends -> "[Anders,Michael]"} | ["Anders","Michael"] | +-------------------------------------------------------------------------+ 3 rows
И затем, если мы объединим весь запрос, мы получим следующее:
$ load csv with headers from "file:/Users/markneedham/Desktop/friendsa.csv" AS row WITH row, split(substring(row.friends, 1, length(row.friends) -2), ",") AS friends UNWIND friends AS friend MERGE (p1:Person {name: row.name}) MERGE (p2:Person {name: friend}) MERGE (p1)-[:FRIENDS_WITH]->(p2);; +-------------------+ | No data returned. | +-------------------+ Nodes created: 5 Relationships created: 6 Properties set: 5 Labels added: 5