Pull to refresh

Comments 7

Создание графа

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

И, поскольку граф есть надстройка над таблицами, на этом уровне вообще никаких констрейнтов не предусмотрено.

как читать направление

То есть получается, что направление задаётся дважды. В структуре - существующее, в запросе.. ммм.. ну, скажем, требуемое. И они обязаны совпадать - иначе будет какая-нибудь бяка типа syntax error или ещё чего. Так, что ли? Если да - то избыточно и странно. А если нет - нужно бы по этому моменту отдельное пояснение.

Как понимаю, речь такая:

С ограничениями — да, в приведённом примере таблица follows допускает и петли, и несколько рёбер между одной парой пользователей: там есть PRIMARY KEY (id) и внешние ключи, но нет UNIQUE (follower_id, followed_id) и CHECK (follower_id <> followed_id).

Но это определяется не уровнем PROPERTY GRAPH, а ограничениями исходной таблицы. Если такие связи нужно запретить, добавляются обычные SQL-констрейнты. Само определение графа бизнес-инварианты поверх данных не вводит.

Для ненаправленной связи записывать ребро дважды не требуется. В определении SQL/PGQ каждое ребро действительно имеет SOURCE и DESTINATION, но в запросе доступны три варианта:

(a)-[e]->(b)a является источником, b — назначением;

(a)<-[e]-(b) — наоборот;

(a)-[e]-(b) — подходит любое из двух направлений.

То есть направление в MATCH не задаёт ребро повторно, а является условием сопоставления. При «неправильной» стрелке синтаксической ошибки не будет — соответствующее ребро просто не попадёт в результат.

Тут бы, конечно, вопросы к автору оригинальной статьи - я перевёл и отвечаю в меру понимания.

Ааа... то есть то, что в описании графа закодировано как SOURCE / DESTINATION, на самом деле есть NODE_1 / NODE_2, а вот уже в тексте запроса задаётся направление отношения. Ну тогда это получается вполне логично - для ненаправленных графов. И требует соответствующей внимательности для направленных, ибо контроль не просто отсутствует, а в принципе синтаксически невозможен.

Да, важный нюанс именно здесь: направление в MATCH — это направление обхода отношения, а не изменение его определения. Связь в графе остаётся направленной, так как она задана через исходную и конечную вершины. Запрос лишь выбирает, идти по ней вперёд, или назад. Для ненаправленных графов это удобно, а для направленных требует аккуратности — обратный обход не делает отношение двунаправленным.

Забавно, что эту же задачу пять лет назад решали не через SQL, а выгрузкой Active Directory в Neo4j – так появился BloodHound: путь атаки через цепочку вложенных групп на чистом LDAP почти не построить, а рекурсивный запрос на такую глубину быстро превращается в нечитаемое месиво. SQL/PGQ – это по сути удобный синтаксис поверх того же рекурсивного соединения таблиц, так что вопрос не "нужен ли новый движок хранения", а справится ли планировщик с тем же обходом рёбер, только записанным через MATCH вместо WITH RECURSIVE.

рекурсивный запрос на такую глубину быстро превращается в нечитаемое месиво

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

Ну вот отличный у Вас пример. SQL/PGQ решает именно проблему выражения таких запросов, но главный вопрос будет не в MATCH вместо WITH RECURSIVE, а в том, насколько хорошо PostgreSQL сможет планировать и выполнять глубокие обходы графа на больших данных.

Sign up to leave a comment.

Articles