Несоответствующие результаты запроса в зависимости от порядка запроса в neo4j - PullRequest
0 голосов
/ 12 июня 2019

[изображение 1 ] [1]

В зависимости от порядка, в котором я запрашиваю 2 отношения, я получаю 2 разных ответа, несмотря на то, что запрос одинаков (насколько я понимаю). Вопрос явно не тот, но я не знаю почему.

MATCH p1=(:Barrier {code: 'B2'})-[:REL1]->()
WITH count(DISTINCT p1) AS failed_B2
MATCH p2=(:Barrier {code: 'B2'})-[:REL2]->()
RETURN count(DISTINCT p2) AS worked_B2, failed_B2

Возвращает 1 и 0 - что правильно

Но наоборот:

MATCH p1=(:Barrier {code: 'B2'})-[:REL2]->()
WITH count(DISTINCT p1) AS failed_B2
MATCH p2=(:Barrier {code: 'B2'})-[:REL1]->()
RETURN count(DISTINCT p2) AS worked_B2, failed_B2

Возвращает 0 и 0 - что неверно

Я хотел бы объединить результаты нескольких запросов, но UNION не работает, поскольку ему нужно сгруппировать результаты в одном столбце, что в моем случае было бы неверным. Мне нужны результаты в разных столбцах.

1 Ответ

0 голосов
/ 12 июня 2019

Так что это интересная вещь, которая сосредотачивается вокруг того, что происходит, когда строки фильтруются (например, когда происходит сбой MATCH или условие WHERE фильтрует строку).

Но сначала нам нужно обратиться к тому, что вы наблюдаливо втором случае: Returns 0 and 0.Я не думаю, что это действительно так, и я хотел бы знать, какую версию Neo4j вы здесь используете.В этом конкретном случае я бы вместо этого ожидал, что строки не будут возвращены, и это ПОЛНОСТЬЮ отличается от строки, возвращаемой с 0 значениями для обоих.

При выполнении запросов Cypher они создают записи (или строки) данных.И операции Cypher выполняются для каждой строки.Поэтому, когда вы выполняете MATCH в какой-то момент в вашем запросе, это выполняется для каждой строки, а когда происходит сбой MATCH, когда такой шаблон не существует (который соответствует вашему предложению WHERE, если имеется), тогда строка отфильтровывается.Это важно, потому что это означает, что любые другие данные в этой записи исчезли и перестали быть адресуемыми.

Второе, что нужно иметь в виду, это то, что мы разрешаем определенным агрегациям, таким как count() и collect(),выполнить , даже если нет строк , поскольку вполне возможно, что у вас может быть запрос, в котором ничего не совпадает, и получение этого числа 0 (или той пустой коллекции, когда вы собираете) является полностью допустимым случаем и должноразрешено.В этих случаях, когда после MATCH или фильтра может вообще не остаться ни одной строки (и из-за отсутствия строк, больше ничего не сможет быть выполнено, так как операции Cypher выполняются для каждой строки, поэтому нет возможности работать, если естьбез строк), count() или collect() приведет к появлению новой строки с этим счетчиком 0 или этой пустой коллекцией.И поскольку теперь есть строка, оставшимся операторам в запросе есть что выполнить, и запрос может продолжить выполнение.

Это то, что происходит в вашем первом случае, когда шаблон p1 не выполняетсуществует, но шаблон p2 существует (один раз).Вот описание того, что происходит:

  1. В первом совпадении ничего не найдено.Строки идут до 0. После выполнения следующих операций ничего не остается.
  2. Вы выполняете автономное агрегирование count() (без других переменных в области, это важно).Это выдает одну строку со счетчиком 0, и это правильно: на графике нет вхождений этого шаблона.
  3. Вы выполняете второй MATCH, и есть запись / строка, которую он должен выполнить при(со значением {failed_B2:0}), и он находит единственное вхождение, и получает его счет (1), и может вывести ожидаемый ответ (1, 0), при этом 1 является счетчиком совпадений шаблона вконец запроса, p2, а 0 - количество совпадений шаблона из первых двух строк запроса, p1.

Теперь давайте посмотрим, что произойдет, когда мы перевернем это.

Во втором запросе теперь есть шаблон p1, который существует один раз на графике, и шаблон p2, который не существует.Вот разбивка, которая происходит:

  1. Первый матч успешно завершен и находит шаблон.
  2. Вы получаете количество найденных шаблонов: 1. Теперь у вас есть одна запись / строка сзначение {failed_B2:1}
  3. Вы выполняете второе MATCH, а шаблон не найден.Запись / строка отфильтрованы.Теперь у вас нет записей / строк, поэтому не только нечего оперировать, но и все, что было ранее в записи / строках, пропало.НЕТ значения failed_B2 для ссылки.
  4. Вы пытаетесь получить счет p2 вместе с failed_B2. Но это не разрешено Cypher, мы разрешаем агрегацию только по 0 строкам, когда это автономный count () или collect (), там нет ссылки на failed_B2, это было уничтожено, когда запись / строка, в которой она находилась, получила отфильтрованы Нет никакого способа обработать это разумно, поскольку ранее существовавшие данные просто отсутствуют (и это правильное поведение). Запрос должен возвращать без строк ... что НЕ совпадает с 0, 0, так как это подразумевает, что вы вернули строку (вот почему я заинтересован в разъяснении этого вопроса с вами).

Что касается того, как вы должны правильно выполнять это, когда вам нужно агрегировать, как это, и вы знаете, что некоторые шаблоны могут не существовать, используйте ОПЦИОНАЛЬНОЕ МАТЧ вместо этого.

Когда вы выбираете опциональное совпадение, оно не отфильтровывает строку, если совпадение не найдено. Вместо этого вновь введенные переменные в шаблоне обнуляются, и когда вы считаете () или collect () больше нуля, он игнорирует их, давая вам правильный счет 0, но не стирая запись / строку, содержащую failed_B2 значение, которое вы также хотите вернуть в конце.

...