neo4j очень медленно обнаруживает все соединения - PullRequest
1 голос
/ 07 мая 2020

Я смоделировал следующую информацию в neo4j. У меня есть 100 вершин A1, A2, ... A100. Каждая вершина отправляет данные в 5 других случайных вершин. Отправляется 10 различных типов данных, и каждый отслеживается с помощью связи между вершинами. Итак, для сценария здесь A1 имеет 50 исходящих ребер с меткой sends-to. Каждый из этих 5 отправляет все 8 видов данных еще 4. Эти 4 отправляют 8 видов данных еще 3. эти 3 отправляют 6 видов данных еще 2. Всего около 100 вершин и 30000 ребер с меткой sends_to с разницей в свойствах. Когда я пишу следующий запрос, чтобы определить, существует ли соединение между A1 и A94, запрос занимает вечность и в конечном итоге не запрашивает увеличение свойства dbms.memory.heap.max_size.

MATCH p=(a:Entity{name: 'A 0'})-[r:SENDS_TO*..]->(d:Entity{name: 'A 94'}) RETURN p;

I увеличил его с 1G до 4G, но по-прежнему сталкивается с той же проблемой. У меня есть указатель на свойство name узла Entity. Это может быть вызвано циклом на графике.

Ответы [ 2 ]

2 голосов
/ 07 мая 2020
Предложение

A MATCH позволяет избежать двойного обхода одного и того же отношения, поэтому циклы, включающие многократное прохождение одного и того же отношения , не будут проблемой.

root проблемы в том, что ваш график чрезвычайно плотный. У вас всего 100 узлов, но в среднем каждый узел имеет 300 отношений. Это означает, что каждый узел имеет примерно 3 отношения к каждому другому узлу. Следовательно, между любыми двумя узлами может быть астрономическое количество уникальных путей, и ваше предложение MATCH пытается найти все эти пути (и сохранить их все в памяти).

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

Например, чтобы найти пути длиной до 6:

MATCH p=(a:Entity{name: 'A 0'})-[r:SENDS_TO*..6]->(d:Entity{name: 'A 94'})
RETURN p;
0 голосов
/ 07 мая 2020

для определения наличия соединения между A1 и A94

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

Есть несколько способов изменить ваш запрос, чтобы сделать меньше работы (но сначала убедитесь, что у вас есть индекс для :Entity(name) начальные поиски):

  1. ОГРАНИЧИТЕ ваши результаты до 1, что приведет к остановке запроса после обнаружения первого совпадения:
MATCH p=(a:Entity{name: 'A 0'})-[r:SENDS_TO*..]->(d:Entity{name: 'A 94'})
RETURN p
LIMIT 1
Используйте функцию ПОИСКПОЗ () для выполнения двунаправленного расширения в ширину, пока не будет найден кратчайший путь между двумя узлами:
MATCH (a:Entity{name: 'A 0'}), (d:Entity{name: 'A 94'})
MATCH p = shortestPath((a)-[r:SENDS_TO*..]->(d))
RETURN p
Используйте процедуры расширения пути из APO C Процедуры, определяя конечный узел и ограничивая результаты до 1:
 MATCH (a:Entity{name: 'A 0'}), (d:Entity{name: 'A 94'})
 CALL apoc.path.spanningTree(a, {relationshipFilter:'SENDS_TO>', endNodes:[d], limit:1}) YIELD path
 RETURN path
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...