Обход связей с запросами графа
Подсказка
Дополнительные сведения см. на вкладке "Текст и изображения ".
Некоторые связи с данными, естественно, представлены в виде сетей, включая социальные подключения, иерархии организации, рекомендации по продуктам и шаблоны обнаружения мошенничества. Хотя эти связи можно моделировать с помощью внешних ключей и соединений, графовые запросы с помощью MATCH оператора обеспечивают более понятный и часто более эффективный способ обхода подключенных данных.
Визуализация структур данных графа
Перед написанием запросов графов он помогает визуализировать порядок упорядочения данных графа. Рассмотрим простую социальную сеть, где люди знают друг друга и покупают продукты:
В этой модели:
- Узлы (поля) представляют такие сущности, как люди и продукты
- Ребра (стрелки ) представляют связи между узлами. Направление стрелки указывает направление отношений (Алиса знает Боба, не обязательно Боб знает Алису).
Замечание
На этой схеме показаны основные понятия графа. Примеры кода в этом уроке используют аналогичные, но упрощенные данные, чтобы сосредоточиться на конкретных функциях.
Общие сведения о возможностях графа
Возможности графа расширяют реляционную модель с выделенными узлами и пограничными таблицами. Узлы представляют такие сущности, как люди, продукты и расположения. Края представляют отношения между ними, например "знает", "приобретено" или "находится в".
Ключевым преимуществом запросов графа является сопоставление шаблонов. Вместо написания сложных многосторонних соединений вы выражаете шаблон, который вам нужен, с помощью синтаксиса в стиле ASCII.
-- Traditional relational approach (multiple joins)
SELECT p1.Name, p2.Name
FROM Person AS p1
INNER JOIN Friendship AS f ON p1.PersonID = f.Person1ID
INNER JOIN Person AS p2 ON f.Person2ID = p2.PersonID;
-- Graph approach (pattern matching)
SELECT Person1.Name, Person2.Name
FROM Person AS Person1, Friendship, Person AS Person2
WHERE MATCH(Person1-(Friendship)->Person2);
Замечание
Таблицы графов полностью совместимы с существующими реляционными функциями. Таблицы графов можно объединить с обычными таблицами, использовать индексы и применять все стандартные операции T-SQL.
Создание таблиц узлов
Таблицы узлов хранят сущности в графе. Создайте их с помощью CREATE TABLE и условия AS NODE:
-- Create a Person node table
CREATE TABLE dbo.Person (
PersonID INT PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(200),
Department NVARCHAR(50)
) AS NODE;
-- Create a Product node table
CREATE TABLE dbo.Product (
ProductID INT PRIMARY KEY,
Name NVARCHAR(200) NOT NULL,
Category NVARCHAR(100),
Price DECIMAL(10, 2)
) AS NODE;
-- Create a Location node table
CREATE TABLE dbo.Location (
LocationID INT PRIMARY KEY,
City NVARCHAR(100) NOT NULL,
CountryRegion NVARCHAR(100) NOT NULL
) AS NODE;
SQL Server автоматически добавляет $node_id столбец в таблицы узлов, которые однозначно идентифицируют каждый узел. Система использует этот столбец внутренне для связей графа.
В следующем примере вставляются четыре записи о людях в таблицу узла данных Person, а затем выполняется запрос таблицы, чтобы отобразить как бизнес-столбцы, так и системно-сгенерированные $node_id. Обратите внимание, что инструкция INSERT использует только определяемые пользователем столбцы. SQL Server автоматически создает $node_id для каждой строки.
-- Insert person data using standard INSERT syntax
INSERT INTO dbo.Person (PersonID, Name, Email, Department)
VALUES
(1, 'Alice Johnson', 'alice@contoso.com', 'Engineering'),
(2, 'Bob Smith', 'bob@contoso.com', 'Marketing'),
(3, 'Carol Davis', 'carol@contoso.com', 'Engineering'),
(4, 'David Lee', 'david@contoso.com', 'Sales');
-- Query shows the system-generated $node_id alongside user columns
SELECT $node_id, PersonID, Name FROM dbo.Person;
Создание пограничных таблиц
Таблицы рёбер представляют связи между узлами. Создайте их с помощью CREATE TABLE и условия AS EDGE:
-- Create a "reports to" relationship edge
CREATE TABLE dbo.ReportsTo (
StartDate DATE,
ReportType NVARCHAR(50)
) AS EDGE;
-- Create a "purchased" relationship edge
CREATE TABLE dbo.Purchased (
PurchaseDate DATE NOT NULL,
Quantity INT NOT NULL,
TotalAmount DECIMAL(10, 2)
) AS EDGE;
-- Create a "knows" relationship edge (social connection)
CREATE TABLE dbo.Knows (
ConnectionDate DATE,
ConnectionStrength INT -- 1-10 scale
) AS EDGE;
SQL Server автоматически добавляет $edge_id$from_idи $to_id столбцы в пограничные таблицы. Вы можете вставить рёбра, указав значения $from_id и $to_id из подключенных узлов, как показано ниже.
-- Alice reports to Bob
INSERT INTO dbo.ReportsTo ($from_id, $to_id, StartDate, ReportType)
SELECT
(SELECT $node_id FROM dbo.Person WHERE Name = 'Alice Johnson'),
(SELECT $node_id FROM dbo.Person WHERE Name = 'Bob Smith'),
'2023-01-15',
'Direct';
-- Create social connections
INSERT INTO dbo.Knows ($from_id, $to_id, ConnectionDate, ConnectionStrength)
SELECT
(SELECT $node_id FROM dbo.Person WHERE Name = 'Alice Johnson'),
(SELECT $node_id FROM dbo.Person WHERE Name = 'Carol Davis'),
'2022-06-01',
8;
Подсказка
Таблицы рёбер могут хранить свойства самого отношения, такие как даты, веса или типы. Это полезно для темпорального анализа или алгоритмов взвешенных графов.
Запрос графов с предложением MATCH
Предложение MATCH использует синтаксис шаблона для указания связей, которые требуется найти. Базовый шаблон использует стрелки для отображения направления отношений:
-- Find who reports to whom
SELECT
Employee.Name AS Employee,
Manager.Name AS Manager,
r.StartDate
FROM dbo.Person AS Employee,
dbo.ReportsTo AS r,
dbo.Person AS Manager
WHERE MATCH(Employee-(r)->Manager);
Направление стрелки имеет значение:
-
(Node1)-(Edge)->(Node2): Edge переходит от Node1 к Node2 -
(Node1)<-(Edge)-(Node2): Edge переходит от Node2 к Node1
В следующем примере мы находим всех людей, которые знают Алису.
SELECT
Connector.Name AS PersonWhoKnowsAlice,
k.ConnectionStrength
FROM dbo.Person AS Connector,
dbo.Knows AS k,
dbo.Person AS Target
WHERE MATCH(Connector-(k)->Target)
AND Target.Name = 'Alice Johnson';
Обход нескольких связей
Запросы с одним переходом находят прямые соединения, но графовые базы данных превосходят в многошаговых переходах. Вы можете связать несколько шаблонов границ в одном MATCH предложении, чтобы следовать путям через несколько связей. Эта возможность позволяет ответить на такие вопросы, как "кто мои друзья?" или "какие продукты купили мои коллеги?" без написания сложных вложенных запросов.
В следующем примере друзья друзей находятся путем цепочки двух отношений KNOWS. Шаблон Person1-(k1)->Person2-(k2)->Person3 начинается с Person1, следует одной связи KNOWS к Person2, а затем следует другой связи KNOWS чтобы достичь Person3.
-- Find friends of friends (2-hop connections)
SELECT DISTINCT
Person1.Name AS Person,
Person3.Name AS FriendOfFriend
FROM dbo.Person AS Person1,
dbo.Knows AS k1,
dbo.Person AS Person2,
dbo.Knows AS k2,
dbo.Person AS Person3
WHERE MATCH(Person1-(k1)->Person2-(k2)->Person3)
AND Person1.Name = 'Alice Johnson'
AND Person3.Name <> Person1.Name; -- Exclude self
Кроме того, можно объединить различные типы связей в одном обходе. В следующем примере пересечение из KNOWS в PURCHASED грани позволяет определить, какие продукты были приобретены людьми, которых знает данный человек.
-- Find products purchased by people in the same department
SELECT DISTINCT
p1.Name AS Person,
p1.Department,
prod.Name AS Product
FROM dbo.Person AS p1,
dbo.Knows AS k,
dbo.Person AS p2,
dbo.Purchased AS pu,
dbo.Product AS prod
WHERE MATCH(p1-(k)->p2-(pu)->prod)
AND p1.Department = p2.Department;
Это важно
Каждый псевдоним граничной таблицы может встречаться только один раз в одном MATCH шаблоне. Чтобы пройти один и тот же тип края несколько раз, используйте отдельные псевдонимы.
Используйте SHORTEST_PATH для обхода переменной длины
Вы можете использовать SHORTEST_PATH, чтобы найти самую короткую связь через переменное количество отношений. Ключевое FOR PATH слово помечает таблицы, участвующие в сопоставлении переменной длины, и квантификаторы, такие как + (один или несколько) или {1,3} (один–три), управляют глубиной прохода.
Следующий пример находит всех людей, достижимых из Алисы за три перехода, и подсчитывает расстояние до каждого.
SELECT
StartPerson.Name,
LAST_VALUE(ReachablePerson.Name) WITHIN GROUP (GRAPH PATH) AS ReachablePerson,
COUNT(ReachablePerson.Name) WITHIN GROUP (GRAPH PATH) AS Distance
FROM dbo.Person AS StartPerson,
dbo.Knows FOR PATH AS k,
dbo.Person FOR PATH AS ReachablePerson
WHERE MATCH(SHORTEST_PATH(StartPerson(-(k)->ReachablePerson){1,3}))
AND StartPerson.Name = 'Alice Johnson';
Выбор между графом и реляционными подходами
Запросы Графа не всегда являются лучшим выбором. При выборе между графом и традиционными реляционными подходами следует учитывать следующие рекомендации:
Используйте запросы графа, когда:
- Связи являются основным фокусом ваших запросов
- Вам нужно проходить через переменные или неизвестные уровни (друзья друзей и так далее).
- Данные естественно образуют сеть (социальные графы, иерархии, маршруты)
- Для шаблонов запросов потребуется много самосоединений в реляционном SQL
- Вы выполняете поиск путей или анализ подключения
Используйте реляционные запросы, когда:
- Связи являются простыми и фиксированными (родительский-дочерний с одним уровнем)
- Вы в основном фильтруете и агрегируете атрибуты сущности
- Модель данных в основном таблична с несколькими связями
- Производительность критична, и индексы на внешних ключах достаточны.
- Ваша команда более знакома с традиционными шаблонами SQL
Устранение распространенных проблем с запросами графа
Запросы Graph имеют уникальные требования к синтаксису, которые могут привести к ошибкам. В следующей таблице описаны распространенные проблемы и способы их устранения.
| Задача | Причина | Решение |
|---|---|---|
| Запрос не возвращает результаты | Направление стрелки в MATCH шаблоне не соответствует тому, как были вставлены края |
Проверьте, как вставлены края. Если $from_id является сотрудником и $to_id является менеджером, стрелка должна указывать от сотрудника к менеджеру. |
| Синтаксическая ошибка с повторяющимися ребрами | Один и тот же псевдоним края, используемый несколько раз в одном MATCH шаблоне |
Создайте отдельные псевдонимы для каждого обхода одного и того же типа ребра. |
SHORTEST_PATH Сбой запроса |
Таблицы граничных узлов, не помеченные FOR PATH |
Добавьте ключевое слово FOR PATH ко всем таблицам, участвующим в сопоставлении переменной длины. |
| Пограничные ссылки на несуществующие узлы | Столбцы бизнес-ключей, используемые вместо значений $node_id |
Используйте вложенные запросы для выбора $node_id из таблиц узлов при вставке ребер. |
Замечание
Таблицы graph и MATCH оператор доступны в SQL Server 2017 и более поздних версиях, а также в Базе данных SQL Azure. Для SHORTEST_PATH функции требуется SQL Server 2019 или более поздней версии. Ознакомьтесь с документацией по вашей платформе для обеспечения доступности определенных компонентов.
Дополнительные сведения о функциях графа см. в разделе " Обработка графов с помощью SQL Server " и MATCH (Transact-SQL).