Неожиданное поведение, объединяющее коллекции в Cypher

#neo4j #cypher

#neo4j #cypher

Вопрос:

Использование http://console.neo4j.org как песочница, я столкнулся со следующим неожиданным поведением:

Оператор 1 — возвращает 1 строку с коллекцией, содержащей узел Neo

 MATCH (n:Crew) 
WHERE n.name="Neo" 
WITH COLLECT(n) AS c1
WITH c1 [] AS c2
RETURN c2
  

Оператор 2 — возвращает 0 строк (неожиданно)

 MATCH (n:Crew) 
WHERE n.name="Neo" 
WITH COLLECT(n) AS c1
MATCH (n:Crew) 
WHERE n.name="NoOne"
WITH c1 COLLECT(n) AS c2
RETURN c2
  

Оператор 3 — возвращает 1 строку, содержащую пустую коллекцию

 MATCH (n:Crew) 
WHERE n.name="NoOne"
WITH COLLECT(n) AS c1
RETURN c1
  

Я не понимаю, почему оператор 2 не возвращает тот же результат, что и оператор 1, потому что он должен возвращать коллекцию, содержащую узел Neo, как и в инструкции 1.
Утверждение 3 показывает, что второе MATCH в утверждении 2 должно приводить к пустой коллекции.

Ожидается ли такое поведение в Cypher? Если это так, я был бы рад небольшому объяснению, которое поможет мне понять это поведение.

Комментарии:

1. Используйте необязательное совпадение в инструкции 2, если СОВПАДЕНИЕ не возвращает данных, тогда (за исключением случаев, когда у вас есть ТОЛЬКО результат агрегирования) оно не вернет строк

Ответ №1:

Я уже сталкивался с таким точным поведением раньше, и это очень расстраивает. Проблема связана со вторым MATCH предложением в запросе 2: если существующая строка результатов (в данном случае ваша единственная строка с c1 ) не возвращает никаких результатов для a MATCH , эта строка будет полностью удалена после этого MATCH предложения, даже если MATCH она сама по себе (без ранее существовавшей строки результатов) возвращаетпустая коллекция. Если вы преобразуете его в an OPTIONAL MATCH , вы сможете сохранить свою результирующую строку, когда совпадений нет.

ОБНОВЛЕНИЕ: смотрите Ниже для более тщательного анализа, но tl, dr заключается в том, что второе COLLECT(n) предложение в инструкции 2 возвращает пустой список, как и в инструкции 3; однако целое предложение WITH c1 COLLECT(n) AS c2 не возвращает строк, потому что после второго нет строк со c1 значением MATCH .

Комментарии:

1. Однако, если от кого-то из Neo нет комментариев, я бы предложил поднять вопрос на GitHub . Это действительно похоже на непоследовательное поведение в отношении агрегаций.

2. Однако я не думаю, что это непоследовательное поведение агрегации; если вы удалите второй c1 оператор from запроса 2 WITH , вы снова получите одну строку с пустой коллекцией. WITH Инструкция , написанная в запросе 2, требует строки со c1 значением для создания новой результирующей строки, из которых она имеет 0, тогда как запрос 3 никогда не требует существующей результирующей строки.

3. И если вы удалите промежуточное WITH звено (так что просто сложите два MATCH оператора, а затем выполните оба COLLECTS в одном WITH statement ), вы получите один пустой список (поскольку ни одна строка не будет соответствовать обоим MATCH эс). Таким образом, поведение агрегации является самосогласованным, WITH именно это вызывает проблему здесь.

Ответ №2:

Я не могу придумать правильного объяснения того, почему 2-й запрос не выполняет то, что вы ожидаете, но если у вас есть несколько необязательных совпадений, которые вы хотите объединить, вы можете использовать для этого НЕОБЯЗАТЕЛЬНОЕ СОВПАДЕНИЕ:

 OPTIONAL MATCH (n:Crew) 
WHERE n.name="Neo" 
WITH COLLECT(n) AS c1
OPTIONAL MATCH (n:Crew) 
WHERE n.name="NoOne"
WITH c1 COLLECT(n) AS c2
RETURN c2