Странный результат, возвращающий условное значение CASE WHEN из apo c .do.when - PullRequest
1 голос
/ 17 марта 2020

У нас есть следующий график

enter image description here

, где серые узлы (: беседа) представляют диалоги между пользователями (: пользовательские розовые узлы). Я создал запрос, который пытается найти текущий разговор между людьми, и если он не существует, то создайте его. В обоих случаях разговор должен быть возвращен. Вот его код:

MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})

OPTIONAL MATCH
    (conv:Conversation)-[:CONDUCTED_BY]->(u1),
    (conv)-[:CONDUCTED_BY]->(u2),
    (conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS { 
    MATCH (conv)-[:CONDUCTED_BY]->(u:User)
    WHERE NOT u IN [u1, u2, u3]
}

CALL apoc.do.when(conv IS NULL, 
    "WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
    "CREATE (conv:Conversation) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
    "RETURN conv AS conv",
    "RETURN $conv AS conv", {u1:u1, u2:u2, u3:u3, conv:conv}) YIELD value
[...WEIRD PART...]

Объяснение: ДОПОЛНИТЕЛЬНЫЙ МАТЧ - пытается найти текущий разговор между Пользователем 1,2,3 - разговор 71 и 72 ГДЕ НЕ СУЩЕСТВУЕТ - исключить другие разговоры между этими пользователями, где могут быть включены другие, такие как Пользователь_4 - 72 В итоге мы получаем только один интересующий нас разговор: 71 ... и теперь появляется странная часть [... странная часть ...]

Если мы заменим [... странная часть ...] с кодом

RETURN value.conv

все хорошо, но прежде чем я пришел к этому решению, я боролся с другим кодом, где в апо c отображении conv: conv не было и else-query был просто ""

WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv
RETURN conv

. Эта часть создавала новый диалог между этими пользователями 1,2,3 каждый раз, когда мы запускаем запрос , Однако, если я заменил его просто на

RETURN value

, он работал правильно, и я имею в виду, что он не создавал новый диалог между пользователями 1,2,3, если он существовал.

ВОПРОС: Я не понимаю, почему следующий код

MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})

OPTIONAL MATCH
    (conv:Conversation)-[:CONDUCTED_BY]->(u1),
    (conv)-[:CONDUCTED_BY]->(u2),
    (conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS { 
    MATCH (conv)-[:CONDUCTED_BY]->(u:User)
    WHERE NOT u IN [u1, u2, u3]
}

CALL apoc.do.when(conv IS NULL, 
    "WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
    "CREATE (conv:Conversation) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
    "RETURN conv",
    "", {u1:u1, u2:u2, u3:u3}) YIELD value

WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv
RETURN conv

может быть ответственным за такое странное поведение.

Ответы [ 2 ]

2 голосов
/ 07 апреля 2020

Это ошибка с интервалом имен экзистенциальных подзапросов. Поскольку conv используется для обозначения чего-то другого, Сайфер переписывает все, кроме двух последних conv до conv@x и последних двух conv@y, чтобы различать guish между ними. Здесь x и y - позиции первого вхождения conv со значением c. Это переписывание не было должным образом распространено на внутренний подзапрос.

Это было исправлено здесь: https://github.com/neo4j/neo4j/commit/2890463ad6d2f323bfbad5cf453f14b42f51c830 и будет включено в следующий выпуск патча Neo4j 4.0.

1 голос
/ 19 марта 2020

Спасибо за разъяснение, я могу воспроизвести это, и это определенно не ожидается. Для меня это похоже на ошибку.

Мы можем обойти эту проблему, переименовав псевдоним, используемый в вашем CASE, в conv2 или в любое значение, отличное от conv. Это должно работать:

MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})

OPTIONAL MATCH
    (conv:Conversation)-[:CONDUCTED_BY]->(u1),
    (conv)-[:CONDUCTED_BY]->(u2),
    (conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS { 
    MATCH (conv)-[:CONDUCTED_BY]->(u:User)
    WHERE NOT u IN [u1, u2, u3]
}

CALL apoc.do.when(conv IS NULL, 
    "WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
    "CREATE (conv:Conversation) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
    "MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
    "RETURN conv",
    "", {u1:u1, u2:u2, u3:u3}) YIELD value

WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv2
RETURN conv2

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

...