Neo4j: реализация мягкого удаления с необязательными отношениями

Я пытаюсь реализовать мягкое удаление в Neo4j. Граф, описанный в Cypher с точки зрения Алисы, выглядит так:

(clyde:User)<-[:FOLLOWS]-(alice:User)-[:LIKES]->(bob:User)

Вместо фактического удаления узла и его связей я

  1. изменить его метку, чтобы его больше нельзя было искать напрямую, т. е. удалить его метку User и добавить метку _User (обратите внимание на подчеркивание)
  2. заменив его отношения, чтобы он больше не мог быть достигнут моими обычными запросами, например. удалив его отношения :FOLLOWS и заменив его отношениями :_FOLLOWS.

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

Результат мягкого удаления Алисы должен быть таким:

(clyde:User)<-[:_FOLLOWS]-(alice:_User)-[:_LIKES]->(bob:User)

Моя первая попытка запроса была такой:

match (user:User {Id: 1})
optional match (user)-[follows:FOLLOWS]->(subject)
remove user:User set user:_User
delete follows
create (user)-[:_FOLLOWS]->(subject);

Проблема в том, что когда этот пользователь ни на кого не подписан, запрос пытается создать связь между user и null, потому что второе совпадение является необязательным, поэтому я получаю эту ошибку: Other node is null.

Моя вторая попытка была такой:

match (user:User {Id: 1})
remove user:User set user:_User
optional match (user)-[follows:FOLLOWS]->(subject)
foreach (f in filter(f in collect({r: follows, n: subject}) where f.r is not null) | delete f.r create (user)-[:_FOLLOWS]->(f.n));

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

SyntaxException: Invalid input '.': expected an identifier character, node labels, a property map, whitespace or ')' (line 1, column 238)

Кто-нибудь знает, как я могу это исправить?

Спасибо, Ян


person Jan Van den bosch    schedule 16.12.2013    source источник


Ответы (1)


Не могли бы вы сначала изменить метку, а затем сопоставить отношения? Затем вы сможете использовать «необязательное» совпадение и не иметь дело со случаями, когда нет следующих отношений, что-то вроде

MATCH (user:User {Id: 1})
REMOVE user:User SET user:_User
WITH user
MATCH (user)-[follows:FOLLOWS]->(subject)
DELETE follows
CREATE (user)-[:_FOLLOWS]->(subject)

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

MATCH (user:User {Id: 1})
OPTIONAL MATCH (user)-[follows:FOLLOWS]->(subject)
REMOVE user:User SET user:_User
WITH user, follows, subject
WHERE subject IS NOT NULL
DELETE follows
CREATE (user)-[:_FOLLOWS]->(subject)

Изменить:
Если проблема в том, что вы хотите сделать это для более чем одного типа отношений, вы можете попробовать

MATCH (user:User {Id: 1})
REMOVE user:User SET user:_User
WITH user 
MATCH (user)-[f:FOLLOWS]->(other)
DELETE f 
CREATE (user)-[:_FOLLOWS]->(other)
WITH user LIMIT 1 
MATCH (user)-[l:LIKES]->(other)
DELETE l 
CREATE user-[:_LIKES]->(other)

Вы можете продолжать расширять его с помощью других типов отношений, просто не забудьте ограничить user при переносе, поскольку множественные совпадения (user)-[r]->(other) означают, что для пользователя есть несколько результатов, или вы будете запускать следующую часть запроса несколько раз.

Я не думаю, что есть общий способ сделать это в шифровании, поскольку вы не можете динамически создавать тип отношений (т.е. CREATE (a)-[newRel:"_"+type(oldRel)]->(b) не работает)

Что-то вроде того, что вы ищете, или я неправильно понимаю ваш вопрос?

person jjaderberg    schedule 16.12.2013
comment
Я думаю, что это работает, если между пользователями существует только один тип отношений, то есть только :FOLLOWS. Но в моем случае на самом деле их больше, например :LIKES, которые тоже нужно заменить. Если у пользователя, например, нет отношений :FOLLOWS и есть хотя бы одно отношение :LIKES, я не думаю, что смогу нести пользователя. - person Jan Van den bosch; 16.12.2013
comment
Не уверен, что вы имеете в виду. Ваш вопрос касался обработки нулевого регистра из необязательного совпадения в вашем запросе (проблема в том, что...), вот что я ответил. - person jjaderberg; 16.12.2013
comment
Конечно, я должен был быть более ясным. Я хочу иметь возможность заменить несколько типов отношений, как необязательных, так и обязательных. Ваше решение не работает, когда у пользователя нет отношений :FOLLOWS, потому что оно использует точное совпадение, и нет пользователя, которого можно было бы перенести в часть :LIKES, потому что он не совпадал в части :FOLLOWS. Именно по этой причине я в первую очередь использовал необязательное совпадение, но это приводит к двум ошибкам в исходном вопросе. - person Jan Van den bosch; 17.12.2013