Недавно меня спросили, как обрабатывать «массив» значений внутри столбца в CSV-файле с помощью инструмента LOAD CSV Neo4j, и хотя я изначально думал, что это невозможно, поскольку каждая ячейка рассматривается как строка, Майкл показал мне способ работать вокруг этого, что я думал, было довольно опрятно.
Допустим, у нас есть файл CSV, представляющий людей и их друзей. Это может выглядеть так:
|
1
2
3
4
|
name,friends"Mark","Michael,Peter""Michael","Peter,Kenny""Kenny","Anders,Michael" |
И мы хотим иметь следующие узлы:
- отметка
- Майкл
- Питер
- Kenny
- Андерс
И следующие отношения друзей:
- Марк -> Майкл
- Марк -> Питер
- Михаил -> Питер
- Майкл -> Кенни
- Кенни -> Андерс
- Кенни -> Майкл
Мы начнем с загрузки CSV-файла и возврата каждой строки:
|
1
2
3
4
5
6
7
8
9
|
$ 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, чтобы получить массив людей, с которыми мы хотим дружить:
|
1
2
3
4
5
6
7
8
9
|
$ 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, чтобы получить пары друзей, которых мы хотим создать:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
$ 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 для создания соответствующих узлов и отношений:
|
1
2
3
4
5
6
7
8
9
|
$ 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: 5Relationships created: 6Properties set: 5Labels added: 5373 ms |
А теперь, если мы запросим базу данных, чтобы вернуть все узлы + отношения …
|
01
02
03
04
05
06
07
08
09
10
11
12
|
$ 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 |
… вы увидите, что у нас есть все. Если вместо списка людей через запятую у нас есть буквенный массив в ячейке …
|
1
2
3
4
|
name,friends"Mark", "[Michael,Peter]""Michael", "[Peter,Kenny]""Kenny", "[Anders,Michael]" |
… Нам нужно настроить часть запроса, которая извлекает наших друзей, чтобы убрать первый и последний символы:
|
1
2
3
4
5
6
7
8
9
|
$ 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 |
И затем, если мы объединим весь запрос, мы получим следующее:
|
1
2
3
4
5
6
7
8
|
$ 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: 5Relationships created: 6Properties set: 5Labels added: 5 |
| Ссылка: | Neo4j: LOAD CSV — Обработка скрытых массивов в ваших CSV-документах от нашего партнера JCG Марка Нидхэма в блоге Марка Нидхэма . |