2015-04-06 2 views
2

Я пытаюсь установить несколько свойств отношений в операции LOAD CSV, где одно из свойств будет установлено ВСЕГДА, а другое будет установлено только в том случае, если эти два узла принадлежат к специфическая метка. Кажется, я не могу заставить его связать несколько операторов SET вместе с условным между ними.Создание/настройка нескольких свойств отношений с условным

Я пытаюсь сделать что-то вдоль линий:

LOAD CSV WITH HEADERS FROM "file:/smalltext.csv" AS line 
MATCH (a:Person { username: line.sender }) 
MATCH (b:Person { username: line.recipient }) 
CREATE UNIQUE (a)-[r:MSGD ]->(b) 
SET r.Msg = coalesce(r.Msg, []) + [line.Msg] 
WITH a,b,r, WHERE a:Geotagged AND b:Geotagged, 
SET r.Distance = (2 * 6371 * asin(sqrt(haversin(radians(a.statusLat - b.statusLat)) + cos(radians(a.statusLat)) * cos(radians(b.statusLat)) * haversin(radians(a.statusLat - b.statusLon))))); 

FYI, формула Расстояние приходит прямо от Neo4j, так что я предполагаю, что это правильно не только математически, но синтаксически, а также.

http://neo4j.com/docs/stable/query-functions-mathematical.html#functions-haversin

Свойство Расстояние должно быть установлено если и только если оба узла помечены как «Geotagged». Причина в том, что функция вычитания (из всех вещей) не знает, как вычесть значение null из числа (или наоборот), и если пользователь не является «Geotagged», значения lat/lon будут равны нулю.

Я попытался помещать создание свойства Msg в оператор CREATE, но это не позволило мне ссылаться на свойство отношений из свойства отношения.

Метка «Geotagged» устанавливается, когда данные импортируются (также в LOAD CSV) и устанавливаются только в том случае, если каждый пользователь имеет информацию о геолокации.

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

Спасибо!

EDIT 1 Я был в состоянии установить широту/долготу 0, если пользователь не геотег на начальном этапе создания узла, однако я предпочел бы не манипулировать данные, если я не совсем есть к.

EDIT 2 После установки всех без Geotagged узлов LAT и LON до 0 и перезапустив импорт отношения, Cypher все еще говорит мне, что не может сделать вычитание с 0 (см):

QueryExecutionKernelException: не знаю, как к Subtract (a.statusLat, b.statusLat) `` 0 'с 33.223`

Теперь я просто посрамлены ... Я бы мог подумать у него не было бы проблем с этим, но это STILL не является хорошим решением, потому что при расчете расстояния между пользователем с геотегами и негеотагами он даст фактические (и ошибочные) результаты, с которыми я не смогу работать.

EDIT 3 Ответ ниже действительно работа, однако причина моего Exception выше потому, что я пытался вычитать на нитях (Дух), так просто запуская их через toFloat() во время вычитания зафиксировал его , Я попытался запустить toFloat() и сохранить результат в БД, однако это полностью удалило поле, если оно вернуло NULL, а это не то поведение, которое я собирался сделать.

Если у кого-то есть возможность запускать оба SET в одной и той же операции LOAD CSV, я был бы очень признателен за понимание, потому что это будет далеко не идеально с моим фактическим набором данных.

ответ

2

Я надеюсь, что это не глупое предложение, но ...

... не было бы проще разделить запрос из на несколько частей? Нельзя сказать, что вы не можете импортировать и обрабатывать один и тот же файл CSV несколькими способами, используя несколько операторов Cypher. Из вашего вопроса я предполагаю, что создание отношения (a)-[r:MSGD ]->(b) и установка свойства r.msg работает отлично. Проблема возникает при попытке условно установить r.distance. Так запустить другую LOAD CSV операцию, например:

LOAD CSV WITH HEADERS FROM "file:/smalltext.csv" AS line 
MATCH (a:Person:Geotagged { username: line.sender })-[r:MSGD]->(b:Person:Geotagged { username: line.recipient }) 
SET r.Distance = (2 * 6371 * asin(sqrt(haversin(radians(a.statusLat - b.statusLat)) + cos(radians(a.statusLat)) * cos(radians(b.statusLat)) * haversin(radians(a.statusLat - b.statusLon))))); 

Это должно соответствовать только тем узлам с обеими :Person и :Geotagged этикетки, которые связаны с MSGD отношениями и, следовательно, удовлетворяет ваше состояние установки r.distance свойства только когда оба Person узлов были помечены Geotagged.

Полный код будет что-то вроде:

LOAD CSV WITH HEADERS FROM "file:/smalltext.csv" AS line 
MATCH (a:Person { username: line.sender }) 
MATCH (b:Person { username: line.recipient }) 
CREATE UNIQUE (a)-[r:MSGD]->(b) 
SET r.Msg = coalesce(r.Msg, []) + [line.Msg] 

LOAD CSV WITH HEADERS FROM "file:/smalltext.csv" AS line 
MATCH (a:Person:Geotagged { username: line.sender })-[r:MSGD]->(b:Person:Geotagged { username: line.recipient }) 
SET r.Distance = (2 * 6371 * asin(sqrt(haversin(radians(a.statusLat - b.statusLat)) + cos(radians(a.statusLat)) * cos(radians(b.statusLat)) * haversin(radians(a.statusLat - b.statusLon))))); 

Надеется, что это полезно.

+0

Нет, не глупое предложение вообще .... Я даже не подумал о чтении в файле во второй раз. С фактическими данными (3 миллиона узлов и несколькими миллионами отношений) это будет намного сложнее, но ... Я все еще думаю, что есть способ сделать все это в одном заявлении, но это действительно сработало. Более подробно в моем OP. – Brooks

Смежные вопросы