Написание запросов шаблонов графа в Microsoft Fabric

Сопоставление шаблонов графа позволяет описать структуру данных, которые вы хотите найти с помощью интуитивно понятного визуального синтаксиса. Вместо объединения таблиц вы записываете шаблоны, которые выглядят как сами связи — узлы, подключенные к краям. В этой статье показано, как создавать запросы шаблонов GQL для распространенных сценариев в графе в Microsoft Fabric.

В примерах используется пример набора данных социальной сети. Полный справочник по синтаксису шаблонов см. в шаблонах графов GQL.

Используйте эту статью, чтобы узнать, как строить и комбинировать узоры узлов, ребра и пути. Для готовых к адаптации задач, таких как поиск соседей или сущностей без связей, см. раздел «Написать общие запросы GQL». Для фильтрации, группировки и агрегирования рабочих процессов см. раздел «Фильтр и агрегирование данных графа».

Необходимые условия

Сопоставьте прямые связи

Базовый шаблон соответствует типу узла, определенному граничному типу и другому типу узла. Синтаксис выглядит как схема связи.

Например, чтобы найти до 100 человек, которые работают в определенной компании:

MATCH (p:Person)-[:workAt]->(c:Company)
RETURN p.firstName, p.lastName, c.name
LIMIT 100

Используйте ненаправленный граничный шаблон, если вы не знаете или не заботитесь о направлении. Например, чтобы найти до 100 взаимных знакомых независимо от того, кто инициировал подключение:

MATCH (a:Person)-[:knows]-(b:Person)
RETURN a.firstName, b.firstName
LIMIT 100

Note

Граф в настоящее время не поддерживает создание ненаправленных ребер, но вы можете делать запросы на ребра в любом направлении с помощью синтаксиса -[:label]-.

Фильтрация шаблонов с использованием inline WHERE

Поместить WHERE внутри паттерна, когда условие определяет, какой узел или ребро может участвовать в матче. Используйте условие MATCH ... WHERE на уровне оператора для постфильтрации завершённого совпадения или отдельное FILTER, когда условие применяется к строке, полученной предыдущим оператором. Расположение предиката может изменить результаты по кратчайшему пути. Для получения дополнительной информации см. Размещение предикатов до или после выбора пути.

Например, чтобы найти людей, родившихся до 1990 года, которые работают в компании, название которой начинается с "A":

MATCH (p:Person WHERE p.birthday < 19900101)-[:workAt]->(c:Company WHERE c.name STARTS WITH 'A')
RETURN p.firstName, p.lastName, c.name

Отфильтруйте свойства ребра, чтобы ограничить соответствие связей. Например, чтобы вернуть только тех, кто начал работать в компании в 2010 году или позже:

MATCH (p:Person)-[w:workAt WHERE w.workFrom >= 2010]->(c:Company)
RETURN p.firstName, c.name, w.workFrom

Сопоставление многоэтапных связей

Используйте шаблоны переменной длины для обхода нескольких прыжков в одном выражении. Укажите минимальное и максимальное количество прыжков с синтаксисом {min,max} .

Например, чтобы найти до 100 человек, находящихся в пределах от двух до четырёх уровней дружбы с Алисой:

MATCH (src:Person WHERE src.firstName = 'Alice')-[:knows]->{2,4}(dst:Person)
RETURN dst.firstName, dst.lastName
LIMIT 100

Чтобы найти до 100 непосредственных и вторичных связей (один или два хопа) из точки Алисы:

MATCH (src:Person WHERE src.firstName = 'Alice')-[:knows]->{1,2}(dst:Person)
RETURN DISTINCT dst.firstName, dst.lastName
LIMIT 100

Управление перемещением с режимами пути

По умолчанию GQL использует WALK, что допускает повторение узлов и рёбер. Используйте другой режим пути, когда нужна более строгая уникальность элементов.

Режим траектории Behavior Следует использовать в следующих случаях...
WALK Допускаются повторяющиеся узлы и рёбра (по умолчанию) Вам нужны все совпадающие маршруты в пределах конечной границы.
TRAIL Нет повторяющихся рёбер Вы хотите избежать повторного трассировки одного и того же ребра, но один и тот же узел может появляться через разные края.
SIMPLE Нет повторяющихся узлов, кроме общего начального и конечного узла, и нет повторяющихся рёбер Вы хотите, чтобы узел не появлялся более одного раза в середине пути, но разрешаете пути, которые возвращаются к началу. Полезно для обнаружения циклов.
ACYCLIC Нет повторяющихся узлов или рёбер Необходимо обеспечить, чтобы ни один узел не встречался в пути более одного раза. Используется для строгих иерархий, происхождения или любого обхода, при котором повторное посещение узла приведет к неправильным результатам.

WALK является самым разрешительным режимом и ACYCLIC является самым строгим.

Для ACYCLIC и SIMPLE уникальность ребра следует из уникальности узла. Путь SIMPLE может замыкаться, возвращаясь к своему первому узлу, но он всё равно не может повторно использовать ребро.

Чтобы проиллюстрировать разницу, рассмотрим путь Алиса → Боб → Кэрол → Боб:

  • WALK — разрешает этот путь. Узлы и края могут повторяться свободно.
  • TRAIL — разрешает этот путь. Боб появляется дважды, но каждое ребро используется по-разному (Алиса→Боб и Кэрол→Боб являются отдельными рёбрами), поэтому рёбра не повторяются.
  • SIMPLE — блокирует этот путь. Боб появляется более одного раза, и SIMPLE позволяет узлу повторяться, только если он является и началом, и концом пути (замкнутый цикл). Здесь Алиса является началом, и Боб является конец, поэтому никаких исключений не применяется.
  • ACYCLIC — блокирует этот путь. Боб появляется более одного раза в любом месте по пути.

В следующем примере показано, как с помощью TRAIL подсчитывать количество различных путей, ведущих к первым 100 человекам, достижимым в сети Алисы в пределах четырех хопов.

MATCH TRAIL (src:Person WHERE src.firstName = 'Alice')-[:knows]->{1,4}(dst:Person)
LET personId = dst.id
RETURN personId, dst.firstName, dst.lastName, count(*) AS pathCount
GROUP BY personId, dst.firstName, dst.lastName
ORDER BY pathCount DESC
LIMIT 100

Используйте ACYCLIC для возвращения до 100 человек, достижимых от Алисы за четыре перехода, где каждый человек на пути уникален.

MATCH ACYCLIC (src:Person WHERE src.firstName = 'Alice')-[:knows]->{1,4}(dst:Person)
RETURN dst.firstName, dst.lastName
LIMIT 100

Режим сопоставления по умолчанию REPEATABLE ELEMENTS позволяет повторно использовать одно и то же ребро разными путями в одном и том же шаблоне графа. Используйте DIFFERENT EDGES или DIFFERENT RELATIONSHIPS, когда каждая связь на всех путях должна отличаться:

MATCH DIFFERENT EDGES
  (p:Person)-[:knows]->(friend:Person),
  (p)-[:knows]->(other:Person)
RETURN p.firstName, friend.firstName, other.firstName
LIMIT 100

Вернуть один короткий путь

ALL — это поиск по пути по умолчанию и возвращает все совпадающие пути. Используйте ANY SHORTEST, чтобы вернуть один кратчайший путь для каждой пары «источник—назначение». Следующий запрос находит один из самых коротких путей от Алисы до Боба:

MATCH p = ANY SHORTEST
  (src:Person WHERE src.firstName = 'Alice')-[:knows]->{1,4}
  (dst:Person WHERE dst.firstName = 'Bob')
RETURN p, path_length(p) AS hopCount

Когда несколько кратчайших путей имеют одинаковую длину, невозможно заранее определить, какой путь будет возвращён. Поиск по путям ALL SHORTEST и ANY не поддерживается.

Расположение предикатов может изменить результат .ANY SHORTEST Встроенные предикаты для узлов и рёбер ограничивают набор допустимых путей, тогда как постфильтр может удалить выбранный путь, не выбирая вместо него более длинный путь. См. Разместить предикаты до или после выбора пути.

Tip

Предпочитайте конечную верхнюю границу для предсказуемой стоимости запроса. Неограниченные ALL WALK узоры не поддерживаются. Неограниченные паттерны с TRAIL, SIMPLEили ACYCLIC заканчиваются за счёт уникальности элементов, но всё равно могут возвращать множество путей. Unbounded ANY SHORTEST WALK поддерживает только определённые формы запроса. См. текущие ограничения.

Использование переменной для выражения общих сущностей

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

Например, чтобы найти до 100 пар людей, которые знают друг друга и работают в одной компании:

MATCH (c:Company)<-[:workAt]-(a:Person)-[:knows]-(b:Person)-[:workAt]->(c)
RETURN a.firstName, b.firstName, c.name
LIMIT 100

Переменная c повторно используется для обоих workAt целевых объектов, поэтому запрос возвращает только пары, где оба человека знают друг друга и работают в одной компании.

Чтобы найти до 100 пар людей, которые оба поставили лайк на один и тот же пост:

MATCH (a:Person)-[:likes]->(post:Post)<-[:likes]-(b:Person)
WHERE a.id < b.id
RETURN a.firstName, b.firstName, post.id
LIMIT 100

Tip

Условие WHERE a.id < b.id предотвращает появление повторяющихся пар (Алиса + Боб и Боб + Алиса) в результатах.

Объединение нескольких шаблонов

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

Например, чтобы найти до 100 человек вместе с их местом работы и городом проживания:

MATCH (p:Person)-[:workAt]->(c:Company),
      (p)-[:isLocatedIn]->(city:City)
RETURN p.firstName, c.name AS company, city.name AS city
LIMIT 100

Общая переменная p соединяет два шаблона. Каждая строка результата представляет одного человека со своей компанией и городом.

Несвязанные паттерны также допустимы, но они образуют декартово произведение своих совпадений. Используйте их только тогда, когда вам специально нужны все комбинации. Для рекомендаций по производительности см. Использование общих переменных для эффективных соединений.

Сопоставление необязательных связей

Используйте OPTIONAL MATCH если связь может не существовать для каждого узла. Строки без совпадения сохраняются со значениями NULL , похожими на SQL LEFT JOIN.

Например, вернуть до 100 человек с названием их компании, включая людей без работодателя (то есть, возвращающих NULL для столбца компании):

MATCH (p:Person)
OPTIONAL MATCH (p)-[:workAt]->(c:Company)
RETURN p.firstName, p.lastName, c.name AS company
LIMIT 100

Используйте IS NULL после OPTIONAL MATCH, чтобы найти до 100 человек, которые не работают в какой-либо компании.

MATCH (p:Person)
OPTIONAL MATCH (p)-[:workAt]->(c:Company)
FILTER c IS NULL
RETURN p.firstName, p.lastName
LIMIT 100