Изменение count () разрезает мои результаты на несколько строк - PullRequest
0 голосов
/ 25 марта 2020

У меня есть иерархия объектов, которые могут иметь отношение к разным типам узлов на разных уровнях. Я пытаюсь запросить один указанный узел c с его отношениями к другому типу узла, а также список его дочерних узлов с их отношениями к другому типу узла. И я хочу подсчитать все различное количество узлов другого типа.

Вот запрос, который работает, но подсчитывает только узлы type2, связанные с объектом верхнего уровня:

MATCH(root:Type1{id: {id}})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, collect(other2) as other2list, count(other2) as other2count
WITH root, collect(child {.*, otherCount: other2count, other: other2list}) as children
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
RETURN root {.*, arm: collect(other1), otherCount: count(other1), children}

Это дает мне именно то, что я ожидаю: один результат, содержащий иерархию с root вверху, список его объектов Type2 и список его дочерних элементов, каждый со своим списком объектов Type2.

Однако я хочу, чтобы otherCount root отсчитывал все объекты Type2, независимо от того, подключены они к root или к любому из его дочерних элементов. Простое добавление отсчетов не сработает, потому что я не хочу считать дубликаты. (Не волнуйтесь, я знаком с DISTINCT; просто исключаю его из этого запроса для целей тестирования.)

Поэтому я пытаюсь передать коллекцию объектов Type2, связанных с дочерними элементами, чтобы сосчитайте их:

MATCH(root:Type1{id: {id}})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, collect(other2) as other2list, count(other2) as other2count
WITH root, collect(child {.*, otherCount: other2count, other: other2list}) as children, other2list
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
RETURN root {.*, arm: collect(other1), otherCount: count(DISTINCT other1+other2list), children}

Теперь я неожиданно получаю несколько строк. Я подозреваю, что это как-то вызвано передачей other2list во втором предложении WITH, но как еще я смогу подсчитать эти объекты?

Есть ли способ сделать это в Cypher?

РЕДАКТИРОВАТЬ: Причина, по которой я не рассчитываю other2count ранее, заключается в том, что я хочу отсеять дубликаты с other1. (Я просто добавил DISTINCT, чтобы прояснить это.)

Итак, у меня была идея: чтобы предотвратить раннюю группировку (как указано @cybersam ниже), я попытался собрать другие2 списки. Вот так:

MATCH(root:Type1{id: {id}})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, collect(other2) as other2list, count(other2) as other2count
WITH root, collect(child {.*, otherCount: other2count, other: other2list}) as children, collect(other2list) as other2lists
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
RETURN root {.*, arm: collect(other1), otherCount: count(DISTINCT other1+other2lists), children}

Это ломает браузер. В какой-то момент мне удалось получить странно искаженный результат от некоторого изменения этого, которое заняло более 9000 мс. Не знаю, почему это такая проблема, но я думаю, что упаковка их в список списков и последующая распаковка этого списка должны быть частью решения.

1 Ответ

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

[ОБНОВЛЕНО]

Агрегирующие функции подобно COLLECT используют все другие неагрегирующие термины в том же предложении WITH или RETURN в качестве ключей группировки. Итак, ваше последнее предложение WITH генерирует несколько строк.

Этот запрос может работать лучше (он использует apo c .coll.toSet , чтобы получить коллекцию отдельных Type2 узлов ):

MATCH(root:Type1{id: $id})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, COLLECT(other2) as o2list
WITH root, COLLECT(child {.*, otherCount: SIZE(o2list), other: o2list}) as children
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
WITH root, children, COLLECT(other1) AS arm
RETURN root {.*, arm: arm, children,
  otherCount: SIZE(apoc.coll.toSet(REDUCE(s = arm, c IN children | s + c.other)))}

Или без использования APO C:

MATCH(root:Type1{id: $id})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, COLLECT(other2) as o2list
WITH root, COLLECT(child {.*, otherCount: SIZE(o2list), other: o2list}) as children
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
WITH root, children, COLLECT(other1) AS arm
UNWIND REDUCE(s = arm, c IN children | s + c.other) AS o
RETURN root {.*, arm: arm, children, otherCount: COUNT(DISTINCT o)}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...