Найти количество узлов не в определенном шаблоне [neo4j]

Я хочу найти все пользовательские узлы, которые не имеют промежуточных соединений с другими пользовательскими узлами.

Базовый график выглядит так:

(User)-[]->(id)

где пользовательский узел может иметь несколько идентификаторов, а некоторые идентификаторы имеют несколько пользовательских узлов. Есть особый паттерн интереса

Match (u:User)-[]->(id)<-[]-(u2:User) 
where u <> u2 AND id(u) < id(u2) 
return u, id, u2

Я хочу найти всех пользователей, НЕ участвующих в этом шаблоне. То есть найдите определенное количество пользователей, у которых нет связи с другим пользователем. Я использую большую машину с 244 ОЗУ, но все, что я пробовал, просто убивает соединение через веб-интерфейс. График содержит 755 млн пользователей и 2 млрд узлов + всего.

Вот они запрос, который ломается

Match (u:User)
Where not ((u)-[]->()<-[]-(:User)
RETURN count(distinct User)

Я приму любое решение, включая APOC, если оно сработает. enter image description here

2
0
93
1

Ответы 1

Основная проблема с вашим текущим запросом заключается в том, что расширение убивает вас. Согласно объяснению, в среднем каждый пользователь подключен примерно к 2 идентификаторам. Таким образом, Neo4j необходимо в четыре раза увеличить объем памяти, который он использует для сохраненных строк (X2 #OfRows и X2 #OfColumnsPerRow в промежуточной таблице, прежде чем он сможет фильтровать подключение к другому пользователю) (Отказ от ответственности: Cypher не гарантирует такое поведение, это просто возможное план, который может произойти)

Итак, вы хотите разработать свой запрос таким образом, чтобы свести к минимуму количество узлов, которые Neo4j должен коснуться, чтобы получить правильные результаты. В вашем случае ваш запрос эквивалентен вопросу о том, сколько пользователей не имеют идентификатора или подключены к идентификатору, который является эксклюзивным для этого пользователя? (Поскольку эти 2 условия являются взаимоисключающими, нам не нужно беспокоиться о перекрытии)

Предполагая, что узлы id имеют метку: ID ...

MATCH (id:ID)
WHERE SIZE((:User)-->(id))=1
WITH COUNT(id) as count
MATCH (u:User)
WHERE NOT (u)-->(:ID)
RETURN count+COUNT(u) as count

Обратите внимание, что края и метки индексируются внутри, поэтому, делая это таким образом, Neo4j фактически ничего не расширяет. Для получения узлов требуется только сканирование по меткам, и сканирование таблицы границ на предмет количества ребер (и, при необходимости, проверка меток на подключенных узлах. Cypher не гарантирует такое поведение).


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

MATCH (id:ID)
WHERE SIZE((id)<--(:User)) > 1
MATCH (id)<--(u:User)
RETURN COUNT((:User))-COUNT(DISTINCT u) as count

Другая ваша проблема - это объем узлов, которые вам, возможно, необходимо подсчитать, и в зависимости от того, что все работает на сервере и что выделено для Neo4j, это может быть немного выше Cypher (апокалипсис может иметь что-то, но я не сделал этого) не найти что-нибудь для подсчета образов). Один из способов обойти это - разместить результаты на странице (с помощью LIMIT и OFFSET), а затем программно запросить количество каждой страницы и суммировать его (это имеет небольшую вероятность ошибки в зависимости от частоты обновлений, но лучше, чем ничего такого)

Другие вопросы по теме