Извлекать все узлы, которые могут быть достигнуты определенным узлом в ориентированном графе

#neo4j #cypher

#neo4j #Шифр

Вопрос:

Учитывая график в Neo4j, который направлен (но может иметь циклы), как я могу получить все узлы, которые доступны из определенного узла с помощью Cypher?

(Также: сколько времени я могу ожидать, что такой запрос займет, если мой график имеет 2 миллиона узлов и, соответственно, 48 миллионов узлов? Приблизительный калибр подойдет, например. менее минуты, нескольких минут, часа)

Ответ №1:

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

В библиотеке процедур APOC есть некоторые процедуры расширения пути, которые направлены на эти варианты использования.

Если вы пытаетесь найти все достижимые узлы из начального узла, пересекая отношения в любом направлении, вы можете использовать apoc.path.subgraphNodes() like so, используя в качестве примера график movies:

 MATCH (n:Movie {title:"The Matrix"})
CALL apoc.path.subgraphNodes(n, {}) YIELD node
RETURN node
  

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

 MATCH (n:Movie {title:"The Matrix"})
CALL apoc.path.subgraphNodes(n, {relationshipFilter:'>'}) YIELD node
RETURN node
  

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

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

1. станут ли память и производительность проблемой, как в случае с ответом, предоставленным @CIAndrews?

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

3. Также, как упоминалось в моем ответе, поведение уникальности Cypher проблематично для этих вариантов использования, поскольку одни и те же узлы будут посещаться снова и снова, и рассматривается каждый путь к ранее посещенному узлу. Процедуры расширения пути в моем ответе избегают этого, и вы должны увидеть значительное улучшение соответственно, но это относится только к графам, где существует несколько путей к одному узлу. Если бы вы сравнили этот подход и подход CIAndrews в DAG (без циклов, только один путь на узел), вы бы увидели аналогичную производительность.

Ответ №2:

Посмотрите здесь, где алгоритм используется для обнаружения сообщества.

Вы можете использовать что-то вроде

 match (n:Movie {title:"The Matrix"})-[r*1..50]-(m) return distinct id(m)
  

но это медленно (протестировано на наборе данных Neo4j movie с 60 тыс. узлов, выше уже выполняется более 10 минут. Вероятно, использование памяти станет проблемой, когда у вас есть набор данных, состоящий из миллионов узлов. Кроме того, это также зависит от того, как подключен ваш набор данных, например, количество связей.