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 сможет планировать и выполнять глубокие обходы графа на больших данных.
Запросы к графам свойств SQL/PGQ в PostgreSQL 19