Статьи

Neo4j: Как работают нулевые значения?

Время от времени я испытываю желание импортировать файл CSV в Neo4j, и я всегда путаюсь с тем, как обрабатывать различные нулевые значения, которые могут скрываться внутри.

Давайте начнем с примера, в котором нет файла CSV. Рассмотрим следующий список и мою попытку вернуть только нулевые значения:

1
2
3
4
5
6
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
WITH value WHERE value = null
RETURN value
  
(no changes, no records)

WITH [null, “null”, “”, “Mark”] AS значения UNWIND значения AS значение WITH значение WHERE value = нулевое значение RETURN (без изменений, без записей)

Хм, это странно. Я бы ожидал, что хотя бы сохраню первое значение в коллекции. А что если мы сделаем обратное?

1
2
3
4
5
6
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
WITH value WHERE value <> null
RETURN value
  
(no changes, no records)

WITH [null, “null”, “”, “Mark”] AS значения UNWIND значения AS значение WITH значение WHERE value <> null RETURN value (без изменений, без записей)

Еще ничего! Давайте попробуем вернуть результат наших сравнений, а не фильтровать строки:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
RETURN value = null AS outcome
  
╒═══════╤═════════╕
"value""outcome"
╞═══════╪═════════╡
null   null    
├───────┼─────────┤
"null" null    
├───────┼─────────┤
""     null    
├───────┼─────────┤
"Mark" null    
└───────┴─────────┘

Итак, это не то, что мы ожидали. У всего есть «результат» «ноль»! Как насчет того, чтобы проверить, является ли значение строкой «Mark»?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
RETURN value = "Mark" AS outcome
  
╒═══════╤═════════╕
"value""outcome"
╞═══════╪═════════╡
null   null    
├───────┼─────────┤
"null" false   
├───────┼─────────┤
""     false   
├───────┼─────────┤
"Mark" true    
└───────┴─────────┘

Из выполнения этого запроса мы узнаем, что если одна сторона сравнения равна нулю, то возвращаемое значение всегда будет нулевым.

Так как же исключить строку, если она нулевая?

Оказывается, мы должны использовать ключевое слово is вместо оператора равенства. Давайте посмотрим, как это выглядит:

01
02
03
04
05
06
07
08
09
10
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
WITH value WHERE value is null
RETURN value
  
╒═══════╕
"value"
╞═══════╡
null  
└───────┘

И положительный случай:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
WITH value WHERE value is not null
RETURN value
  
╒═══════╕
"value"
╞═══════╡
"null"
├───────┤
""    
├───────┤
"Mark"
└───────┘

Что если мы хотим избавиться от пустых строк?

01
02
03
04
05
06
07
08
09
10
11
12
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
WITH value WHERE value <> ""
RETURN value
  
╒═══════╕
"value"
╞═══════╡
"null"
├───────┤
"Mark"
└───────┘

Интересно, что это также избавляет от нулевого значения, которое я не ожидал. Но если мы ищем значения, соответствующие пустой строке:

01
02
03
04
05
06
07
08
09
10
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
WITH value WHERE value = ""
RETURN value
  
╒═══════╕
"value"
╞═══════╡
""    
└───────┘

Этого тоже нет! Хм, что здесь происходит:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
WITH [null, "null", "", "Mark"] AS values
UNWIND values AS value
RETURN value, value = "" AS isEmpty, value <> "" AS isNotEmpty
  
╒═══════╤═════════╤════════════╕
"value""isEmpty""isNotEmpty"
╞═══════╪═════════╪════════════╡
null   null     null       
├───────┼─────────┼────────────┤
"null" false    true       
├───────┼─────────┼────────────┤
""     true     false      
├───────┼─────────┼────────────┤
"Mark" false    true       
└───────┴─────────┴────────────┘

нулевые значения, по-видимому, отфильтровываются для каждого типа совпадения на равенство, если только мы явно не проверим, что значение равно нулю.

Итак, как мы используем эти знания при анализе файлов CSV с помощью инструмента загрузки CSV Neo4j?

Допустим, у нас есть файл CSV, который выглядит следующим образом:

1
2
3
4
5
6
$ cat nulls.csv
name,company
"Mark",
"Michael",""
"Will",null
"Ryan","Neo4j"

$ cat nulls.csv name, компания «Марк», «Майкл», »,« Уилл », ноль« Райан »,« Neo4j »

Таким образом, ни одна из первых трех строк не имеет значения для «компании». У меня вообще нет никакого значения, у Майкла пустая строка, а у Уилла нулевое значение. Давайте посмотрим, как LOAD CSV интерпретирует это:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
load csv with headers from "file:///nulls.csv" AS row
RETURN row
  
╒═════════════════════════════════╕
"row"                           
╞═════════════════════════════════╡
│{"name":"Mark","company":null}   │
├─────────────────────────────────┤
│{"name":"Michael","company":""}  │
├─────────────────────────────────┤
│{"name":"Will","company":"null"} │
├─────────────────────────────────┤
│{"name":"Ryan","company":"Neo4j"}│
└─────────────────────────────────┘

Мы получили полный охват всех комбинаций сверху. Мы хотели бы создать узел Person для каждой строки, но только создать узел Company и связанный с ним «WORKS_FOR» Relationshp, если определена фактическая компания — мы не хотим создавать пустую компанию.

Поэтому мы хотим создать только узел компании и отношение «WORKS_FOR» для строки Райана.

Следующий запрос делает трюк:

1
2
3
4
5
6
7
8
load csv with headers from "file:///nulls.csv" AS row
MERGE (p:Person {name: row.name})
WITH p, row
WHERE row.company <> "" AND row.company <> "null"
MERGE (c:Company {name: row.company})
MERGE (p)-[:WORKS_FOR]->(c)
  
Added 5 labels, created 5 nodes, set 5 properties, created 1 relationship, statement completed in 117 ms.

загрузить csv с заголовками из «file: ///nulls.csv» как строка MERGE (p: Person {name: row.name}) WITH p, строка WHERE row.company <> «» И row.company <> «null ”MERGE (c: Company {name: row.company}) MERGE (p) — [: WORKS_FOR] -> (c) Добавлено 5 меток, создано 5 узлов, установлено 5 свойств, создано 1 отношение, оператор завершен за 117 мс.

И если мы представим, что было создано:

Отлично. Возможно, это поведение очевидно, но оно всегда сбивает меня с толку, так что, надеюсь, это будет полезно и кому-то еще!

Ссылка: Neo4j: Как работают нулевые значения? от нашего партнера JCG Марка Нидхэма в блоге Марка Нидхэма .