Проблема с производительностью самого низкого общего предка Neo4j Cypher

Я пытаюсь создать приложение в spring-neo4j, используя графический репозиторий. Одним из требований является нахождение младшего общего предка (lca) между двумя дочерними узлами.

В настоящее время я использую следующий запрос для достижения этой цели:

 @Query("MATCH path = (c1:Concept)-[r:Relation*{type: 'Is a'}]->(ca:Concept)<-[r:Relation*{type: 'Is a'}]-(c2:Concept) 
      WHERE c1.conceptID = {conceptId1} AND c2.conceptID = {conceptId2}
      RETURN ca ORDER BY length(path) LIMIT 1")

Concept findLowestCommonAncestor(@Param("conceptId1") Long conceptId1, @Param("conceptId2") Long conceptId2);

Проблема здесь в производительности. Изначально мой граф состоял из 330 000 узлов и 2 000 000 отношений. Интересующие меня отношения имеют тип: "Is a". Они перемещаются только вверх по дереву (соединяя дочерние узлы с родительскими узлами). Максимальное расстояние вверх — 3.

Это древовидная структура:

Пример древовидной структуры

Поскольку у меня есть несколько древовидных структур, подобных этой, я решил добавить корневой узел, соединяющий все различные древовидные структуры вместе. Так что ЛКА всегда найдется. Но добавление этого корневого узла резко изменило мою производительность: с 558 мс до 562286 мс.

Я знаю, что добавление корневого узла повлияет на производительность, но это не должно быть так сильно, верно? И если да, то есть ли лучший способ рассчитать lca?

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


person Bart Praats    schedule 23.02.2016    source источник
comment
Можете ли вы профилировать свой запрос с помощью веб-интерфейса neo4j? neo4j.com/docs/stable/how-do- i-profile-a-query.html, чтобы показать нам план выполнения, загрузите результат в виде изображения и предоставьте ссылку, ответ должен быть в этом профиле.   -  person Supamiu    schedule 23.02.2016
comment
Привет, спасибо за ваш ответ. Я сделал то, что вы просили меня для случая, когда корневой узел еще не был добавлен. Иначе это заняло бы слишком много времени. Надеюсь, этого достаточно... i.imgur.com/xskg39J.png   -  person Bart Praats    schedule 23.02.2016
comment
Цель состояла в том, чтобы сравнить запрос без корневого узла и другой, поэтому, если вы можете получить профиль запроса с корневым узлом, я уверен, что вы сможете найти, в чем проблема. О, подождите, я нашел проблему, я думаю. Каков ваш ярлык отношений? :Relation?   -  person Supamiu    schedule 23.02.2016
comment
Да, в самом деле. Поскольку все отношения будут иметь одну и ту же метку, я выбрал имя метки по умолчанию... Это вызывает проблемы с производительностью?   -  person Bart Praats    schedule 23.02.2016


Ответы (2)


Во-первых, я хочу поблагодарить @Supamiu за помощь в моем вопросе.

Хотя его ответа, вероятно, достаточно для некоторых случаев. В моем случае изменить модель было невозможно.

Удивительно, но мне удалось повысить производительность, просто изменив шифрованный запрос.

Мой исходный запрос:

MATCH path = (c1:Concept)-[r1:Relation*{type: "Is a"}]->(ca:Concept)<-[r2:Relation*{type: "Is a"}]-(c2:Concept)
WHERE c1.conceptID=35104066 AND c2.conceptID=35808913
RETURN ca
ORDER BY length(path)
LIMIT 1

ПРОФИЛЬ: http://i.imgur.com/14yleCo.png

Я изменил его на:

MATCH (c1:Concept {conceptID: 35104066})-[:Relation*{type: "Is a"}]->(p1:Concept)
MATCH (:Concept {conceptID: 35808913})-[:Relation*{type: "Is a"}]->(p2:Concept)
WHERE p1.conceptID = p2.conceptID
MATCH path = (c1)-[:Relation*{type: "Is a"}]->(p1)
RETURN p1
ORDER BY length(path)
LIMIT 1

ПРОФИЛЬ: http://imgur.com/YCDDF5H

Это дает моему младшему общему предку примерно 100 мс, что является значительным улучшением!

Я до сих пор не совсем понимаю, почему это имеет такое значение. Но я думаю, что одна из причин в том, что я использую древовидную структуру. Я думаю, почему-то во втором запросе Cypher ищет только вверх по дереву, что приводит к меньшему количеству отношений к поиску. Так что в структуре блоба это не очень поможет, я думаю.

Может кто-то может подтвердить это?

person Bart Praats    schedule 25.02.2016

Ваша проблема связана с проблемой метки отношения, позвольте мне объяснить:

Прежде всего, ваш запрос соответствует бесконечной глубине отношения :Relation.

Вы сказали, что каждое дерево в вашей базе данных теперь связано с корневым узлом, я думаю, оно связано с корневым узлом с помощью отношения :Relation.

Таким образом, когда вы сопоставляете каждое отношение, помеченное :Relation, с бесконечной глубиной, оно будет соответствовать всем отношениям в вашей базе данных до фильтрации по свойству type. Вот почему этот корневой узел добавил такую ​​проблему производительности, потому что он соединяет все узлы одним и тем же отношением.

Как это исправить?

Измените метки отношения, используйте их вместо сопоставления со свойством:

(ca:Concept{properties...})-[:IS_A]->(ca2:Concept)

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

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

Другим решением было бы добавить максимальную глубину в ваш запрос, поскольку ваше дерево имеет максимум 3 уровня, вы можете ограничить глубину отношений до 3. Но первое решение, на мой взгляд, намного лучше, потому что создание только одного типа отношений и фильтрация использование их свойств является плохой практикой в ​​neo4j.

РЕДАКТИРОВАТЬ

Итак, вот ваш первый профиль: http://i.imgur.com/xskg39J.png

Вы можете видеть здесь, что соответствие [:Relation*] имеет 31 328 совпадений до фильтрации, что довольно хорошо.

Во втором профиле (с корневым узлом): http://i.imgur.com/14yleCo.png

Вы можете видеть, что одно и то же сопоставление получило почти 2 000 000 совпадений, что после фильтрации составляет 500 000... Это слишком много.

Я думаю, что решение Path, вы можете взглянуть на это:

Проблема не может быть решена только с помощью «лучшего» шифрованного запроса. Я думаю, что вашу проблему можно решить с помощью лучшей модели данных, но трудно найти какую именно, не работая над самим проектом. Единственное, что я могу предоставить, это руководство: http://neo4j.com/developer/guide-data-modeling/

person Supamiu    schedule 23.02.2016
comment
Хорошо, это действительно один из способов решить часть проблемы. Но допустим, я использую метку вместо свойства. Теперь мои узлы связаны с по-разному помеченными отношениями, и мой запрос больше не будет работать. Даже если я изменю только метку отношения с верхних узлов (SOC) на корневой узел, я не смогу найти LCA для узлов, подключенных через корневой узел. И если когда-нибудь (по какой-то причине) в моем дереве понадобится дополнительный уровень, проблема с производительностью возникнет снова. Могу ли я как-то изменить свой запрос, чтобы он был более эффективным в текущей структуре графа? - person Bart Praats; 23.02.2016
comment
не могли бы вы предоставить набор данных или план выполнения? Я не знаю, как вы можете оптимизировать свой запрос, используя только ваши объяснения. - person Supamiu; 23.02.2016
comment
Странно, ваш первый план выполнения (i.imgur.com/xskg39J.png) и другой (i.imgur.com/i504fpN.png) показывает прямо противоположное вашему проблема. Первый план выполнения кажется намного медленнее, чем второй, из-за 31k db хитов на 4-м шаге. Я действительно не знаю, в чем здесь проблема ... Я думаю, вам придется подождать, пока некоторые шифровальные звери вам помогут :/ - person Supamiu; 24.02.2016
comment
Ой извините, первый на самом деле создан с помощью PROFILE, второй был создан с помощью EXPLAIN. Я был сбит с толку. Какой из обоих вы хотите? - person Bart Praats; 24.02.2016
comment
PROFILE, потому что EXPLAIN не показывает достаточно подробностей. - person Supamiu; 24.02.2016
comment
Хорошо, я отредактирую ответ, окажу всю возможную помощь. - person Supamiu; 24.02.2016