Présentation des requêtes Spanner Graph

Ce document explique comment interroger des graphiques de propriétés dans Spanner Graph. Les exemples de cette section utilisent le schéma de graphique que vous créez dans la section Configurer et interroger Spanner Graph, illustré dans le diagramme suivant:

Exemple de schéma Spanner Graph.

Exécuter une requête Spanner Graph

Vous pouvez exécuter des requêtes de graphe Spanner de différentes manières:

Structure de requête Spanner Graph

Cette section décrit chaque composant de la requête en détail.

L'exemple suivant illustre la structure de base d'une requête de graphique Spanner.

Exemple de structure de requête Spanner Graph.

Spanner Graph vous permet de créer plusieurs graphiques dans une base de données. La requête commence par spécifier le graphique cible, FinGraph, à l'aide de la clause GRAPH.

Correspondance de modèles de graphiques

La mise en correspondance de modèles de graphique permet de trouver des modèles spécifiques dans votre graphique. Les modèles les plus élémentaires sont les modèles d'éléments (modèles de nœuds et de bords), qui correspondent aux éléments de graphique (nœuds et bords, respectivement). Les motifs d'éléments peuvent être composés en motifs de tracés et en motifs plus complexes.

Modèles de nœuds

Un modèle de nœud est un modèle qui correspond aux nœuds de votre graphique. Ce modèle comprend une paire de parenthèses correspondante, qui peut éventuellement contenir une variable de modèle de graphique, une expression de libellé et des filtres de propriété.

Rechercher tous les nœuds

La requête suivante renvoie tous les nœuds du graphique. La variable n, appelée variable de modèle de graphique, se lie aux nœuds correspondants. Dans ce cas, le modèle de nœud correspond à tous les nœuds du graphique.

GRAPH FinGraph
MATCH (n)
RETURN LABELS(n) AS label, n.id;

Résultat

La requête renvoie label et id comme suit:

étiquette id
Compte 7
Compte 16
Compte 20
Personne 1
Personne 2
Personne 3

Rechercher tous les nœuds avec un libellé spécifique

La requête suivante correspond à tous les nœuds du graphique associés au libellé Person. La requête renvoie les propriétés label et id, name des nœuds correspondants.

GRAPH FinGraph
MATCH (p:Person)
RETURN LABELS(p) AS label, p.id, p.name;

Résultat

étiquette id nom
Personne 1 Alex
Personne 2 Dana
Personne 3 Lee

Rechercher tous les nœuds correspondant à une expression de libellé

Vous pouvez créer une expression de libellé avec un ou plusieurs opérateurs logiques.

La requête suivante correspond à tous les nœuds du graphique qui portent le libellé Person ou Account. L'ensemble des propriétés exposées par la variable de modèle de graphique n est le sur-ensemble des propriétés exposées par les nœuds portant le libellé Person ou Account.

GRAPH FinGraph
MATCH (n:Person|Account)
RETURN LABELS(n) AS label, n.id, n.birthday, n.create_time;
  • Dans les résultats, tous les nœuds ont la propriété id.
  • Les nœuds correspondant au libellé Account possèdent la propriété create_time, mais pas la propriété birthday. Un NULL est renvoyé pour la propriété birthday pour ces nœuds.
  • Les nœuds correspondant au libellé Person possèdent la propriété birthday, mais pas la propriété create_time. Un NULL est renvoyé pour la propriété create_time pour ces nœuds.

Résultat

étiquette id anniversaire create_time
Compte 7 NULL 2020-01-10T14:22:20.222Z
Compte 16 NULL 2020-01-28T01:55:09.206Z
Compte 20 NULL 2020-02-18T13:44:20.655Z
Personne 1 1991-12-21T08:00:00Z NULL
Personne 2 1980-10-31T08:00:00Z NULL
Personne 3 1986-12-07T08:00:00Z NULL

Pour en savoir plus sur les règles d'expression des libellés, consultez la section Expression de libellé.

Rechercher tous les nœuds correspondant à l'expression de libellé et au filtre de propriété

La requête suivante correspond à tous les nœuds du graphique portant le libellé Person et pour lesquels la propriété id est égale à 1.

GRAPH FinGraph
MATCH (p:Person {id: 1})
RETURN LABELS(p) AS label, p.id, p.name, p.birthday;

Résultat

étiquette id nom anniversaire
Personne 1 Alex 1991-12-21T08:00:00Z

Vous pouvez utiliser la clause WHERE pour créer des conditions de filtrage plus complexes sur les libellés et les propriétés.

La requête suivante correspond à tous les nœuds du graphique portant l'étiquette Person, et la propriété birthday est placée avant 1990-01-10.

GRAPH FinGraph
MATCH (p:Person WHERE p.birthday < '1990-01-10')
RETURN LABELS(p) AS label, p.name, p.birthday;

Résultat

étiquette nom anniversaire
Personne Dana 1980-10-31T08:00:00Z
Personne Lee 1986-12-07T08:00:00Z

Modèles de bord

Un motif d'arête correspond aux arêtes ou aux relations entre les nœuds. Les motifs d'arête sont placés entre crochets [] avec les symboles -, -> ou <- pour indiquer les directions.

Comme pour les modèles de nœuds, les variables de modèle de graphique sont utilisées pour lier les éléments d'arête correspondants.

Rechercher tous les bords avec des libellés correspondants

La requête suivante renvoie tous les arcs du graphique associés à l'étiquette Owns. La variable de modèle de graphique e est liée aux arêtes correspondantes.

GRAPH FinGraph
MATCH -[e:Owns]->
RETURN e.id AS owner_id, e.account_id;

Résultat

owner_id account_id
1 7
3 16
2 20

Rechercher toutes les arêtes correspondant à l'expression de libellé et au filtre de propriété

Comme un modèle de nœud, un modèle d'arête peut utiliser des expressions de libellé, une spécification de propriété et des clauses WHERE, comme illustré dans la requête suivante. La requête recherche tous les bords étiquetés avec Owns et ayant la propriété create_time au cours d'une période spécifiée.

GRAPH FinGraph
MATCH -[e:Owns WHERE e.create_time > '2020-01-14'
                 AND e.create_time < '2020-05-14']->
RETURN e.id AS owner_id, e.create_time, e.account_id;

Résultat

owner_id create_time account_id
2 2020-01-28T01:55:09.206Z 20
3 2020-02-18T13:44:20.655Z 16

Trouver toutes les arêtes à l'aide de n'importe quel modèle d'arête de direction

Bien que tous les arcs du graphique Spanner soient orientés, vous pouvez utiliser le modèle d'arc any direction -[]- dans une requête pour faire correspondre les arcs dans les deux sens.

La requête suivante recherche tous les transferts impliquant un compte bloqué.

GRAPH FinGraph
MATCH (account:Account)-[transfer:Transfers]-(:Account)
WHERE account.is_blocked
RETURN transfer.order_number, transfer.amount;

Résultat

order_number amount
304330008004315 300
304120005529714 100
103650009791820 300
302290001255747 200

Formats de chemin

Un modèle de chemin est construit à partir de modèles de nœuds et d'arêtes alternés.

Rechercher tous les chemins d'un nœud avec des filtres de libellé et de propriété spécifiés, à l'aide d'un modèle de chemin

La requête suivante recherche tous les transferts vers un compte lancés à partir d'un compte appartenant à Person avec id égal à 2.

Chaque résultat correspondant représente un chemin d'{id: 2} Person via un Account connecté à l'aide de l'arête Owns, vers un autre Account à l'aide de l'arête Transfers.

GRAPH FinGraph
MATCH
  (p:Person {id: 2})-[:Owns]->(account:Account)-[t:Transfers]->
  (to_account:Account)
RETURN
  p.id AS sender_id, account.id AS from_id, to_account.id AS to_id;

Résultat

sender_id from_id to_id
2 20 7
2 20 16

Modèles de chemin quantifiés

Un modèle quantifié permet de répéter un modèle dans une plage spécifiée.

Correspondre à un schéma de bord quantifié

La requête suivante recherche tous les comptes de destination à un, deux ou trois transferts d'un Account source avec id égal à 7, à l'exception de lui-même.

Format de bord postfixé avec le quantificateur {1, 3}.

GRAPH FinGraph
MATCH (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account)
WHERE src != dst
RETURN src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length, dst.id AS dst_account_id;

Résultat

src_account_id path_length dst_account_id
7 1 16
7 1 16
7 1 16
7 3 16
7 3 16
7 2 20
7 2 20

L'exemple précédent utilise la fonction ARRAY_LENGTH pour accéder à la e group variable. Pour en savoir plus, consultez la section Variable de groupe d'accès.

Certaines lignes de l'exemple de résultats sont répétées, car il peut y avoir plusieurs chemins entre la même paire de comptes src et dst qui correspondent au modèle.

Correspondre à un format de chemin d'accès quantifié

La requête suivante recherche des chemins entre des nœuds Account avec un à deux arcs Transfers via des comptes intermédiaires bloqués.

Le modèle de chemin d'accès entre parenthèses est quantifié, et la clause WHERE est utilisée entre parenthèses pour spécifier les conditions du modèle répété.

GRAPH FinGraph
MATCH
  (src:Account)
  ((:Account)-[:Transfers]->(interm:Account) WHERE interm.is_blocked){1,2}
    -[:Transfers]->(dst:Account)
RETURN src.id AS src_account_id, dst.id AS dst_account_id;

Résultat

src_account_id dst_account_id
7 20
7 20
20 20

Variables de groupe

Une variable de modèle de graphique déclarée dans un modèle quantifié est considérée comme une variable de groupe lorsqu'elle est accessible en dehors du modèle quantifié. Elle se lie à un tableau d'éléments graphiques correspondants.

Vous pouvez accéder à une variable de groupe en tant que tableau dans lequel les éléments du graphique sont conservés dans l'ordre d'apparition le long des chemins correspondants. Vous pouvez agréger une variable de groupe à l'aide de l'agrégation horizontale.

Variable de groupe d'accès

Dans l'exemple suivant, la variable e est accessible comme suit:

  • Variable de modèle de graphique liée à un seul arc dans la clause e.amount > 100 WHERE (dans le modèle quantifié).
  • Variable de groupe liée à un tableau d'éléments de bord dans ARRAY_LENGTH(e) dans l'instruction RETURN (en dehors du modèle quantifié).
  • Variable de groupe liée à un tableau d'éléments de bord, qui est agrégée par SUM(e.amount) en dehors du modèle quantifié. Il s'agit d'un exemple d'agrégation horizontale.
GRAPH FinGraph
MATCH
  (src:Account {id: 7})-[e:Transfers WHERE e.amount > 100]->{0,2}
  (dst:Account)
WHERE src.id != dst.id
LET total_amount = SUM(e.amount)
RETURN
  src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length,
  total_amount, dst.id AS dst_account_id;

Résultat

src_account_id path_length total_amount dst_account_id
7 1 300 16
7 2 600 20

"Tout" et "Tout chemin le plus court"

Pour limiter les chemins mis en correspondance dans chaque groupe de chemins partageant les mêmes nœuds source et de destination, vous pouvez utiliser le préfixe de recherche de chemin ANY ou ANY SHORTEST. Vous ne pouvez appliquer ces préfixes qu'avant un modèle de chemin d'accès complet et non entre parenthèses.

Correspondre à l'une de ces conditions

La requête suivante recherche tous les comptes uniques accessibles qui se trouvent à une ou deux Transfers d'un nœud Account donné.

Le préfixe de recherche de chemin ANY garantit qu'un seul chemin entre une paire unique de nœuds Account src et dst est renvoyé. Dans l'exemple suivant, même si vous pouvez accéder au nœud Account avec {id: 16} de deux manières différentes à partir du nœud Account source, les résultats n'incluent qu'un seul chemin.

GRAPH FinGraph
MATCH ANY (src:Account {id: 7})-[e:Transfers]->{1,2}(dst:Account)
LET ids_in_path = ARRAY(SELECT e.to_id FROM UNNEST(e) AS e)
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ids_in_path;

Résultat

src_account_id dst_account_id ids_in_path
7 16 16
7 20 16,20

Modèles de graphiques

Un modèle de graphique se compose d'un ou de plusieurs modèles de chemin, séparés par une virgule ,. Les modèles de graphique peuvent contenir une clause WHERE, qui vous permet d'accéder à toutes les variables de modèle de graphique dans les modèles de chemin pour former des conditions de filtrage. Chaque modèle de chemin génère une collection de chemins.

Correspondre à l'aide d'un modèle de graphique

La requête suivante identifie les comptes intermédiaires et leurs propriétaires impliqués dans des transactions d'un montant supérieur à 200 €, par le biais desquelles des fonds sont transférés d'un compte source vers un compte bloqué.

Les formats de chemin suivants constituent le modèle de graphique:

  • Le premier modèle trouve les chemins où le transfert s'effectue d'un compte vers un compte bloqué à l'aide d'un compte intermédiaire.
  • Le deuxième modèle recherche les chemins d'accès d'un compte à son propriétaire.

La variable interm sert de lien commun entre les deux modèles de chemin, ce qui nécessite que interm fasse référence au même nœud d'élément dans les deux modèles de chemin. Cela crée une opération d'équivalence en fonction de la variable interm.

GRAPH FinGraph
MATCH
  (src:Account)-[t1:Transfers]->(interm:Account)-[t2:Transfers]->(dst:Account),
  (interm)<-[:Owns]-(p:Person)
WHERE dst.is_blocked = TRUE AND t1.amount > 200 AND t2.amount > 200
RETURN
  src.id AS src_account_id, dst.id AS dst_account_id,
  interm.id AS interm_account_id, p.id AS owner_id;

Résultat

src_account_id dst_account_id interm_account_id owner_id
20 16 7 1

Instructions de requête linéaires

Vous pouvez associer plusieurs instructions de graphique pour former une instruction de requête linéaire. Les instructions sont exécutées dans l'ordre dans lequel elles apparaissent dans la requête.

  • Chaque instruction utilise la sortie de l'instruction précédente comme entrée. La valeur d'entrée est vide pour la première instruction.
  • Le résultat de la dernière instruction est le résultat final.

Déterminer le montant maximal de transfert vers un compte bloqué

La requête suivante recherche le compte et son propriétaire ayant effectué le plus gros transfert sortant vers un compte bloqué.

GRAPH FinGraph
MATCH (src_account:Account)-[transfer:Transfers]->(dst_account:Account)
WHERE dst_account.is_blocked
ORDER BY transfer.amount DESC
LIMIT 1
MATCH (src_account:Account)<-[owns:Owns]-(owner:Person)
RETURN src_account.id AS account_id, owner.name AS owner_name;

Le tableau suivant illustre la transmission des résultats intermédiaires aux instructions. Par souci de concision, seules certaines propriétés des résultats intermédiaires sont affichées.

Propos Résultat intermédiaire (abrégé)
MATCH
  (src_account:Account)
    -[transfer:Transfers]->
  (dst_account:Account)
WHERE dst_account.is_blocked
src_account transfert dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}

ORDER BY transfer.amount DESC
src_account transfert dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}

LIMIT 1
src_account transfert dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}

MATCH
  (src_account:Account)
    <-[owns:Owns]-
  (owner:Person)
src_account transfert dst_account est propriétaire Propriétaire
{id: 7} {amount: 300.0} {id: 16, is_blocked: true} {person_id: 1, account_id: 7} {id: 1, name: Alex}

RETURN
  src_account.id AS account_id,
  owner.name AS owner_name
account_id owner_name
7 Alex

Résultat

account_id owner_name
7 Alex

Instruction return

L'instruction de retour définit ce qui doit être renvoyé à partir des modèles correspondants. Il peut accéder aux variables de modèle de graphique, contenir des expressions et d'autres clauses telles que ORDER_BY et GROUP_BY. Consultez l'instruction RETURN.

Notez que Spanner Graph ne permet pas de renvoyer des éléments de graphique en tant que résultats de requête. Pour renvoyer l'élément graphique complet, utilisez la fonction TO_JSON ou la fonction SAFE_TO_JSON. Nous vous recommandons d'utiliser SAFE_TO_JSON.

Renvoyer les éléments du graphique au format JSON

GRAPH FinGraph
MATCH (n:Account {id: 7})
-- Returning a graph element in the final results is NOT allowed. Instead, use
-- the TO_JSON function or explicitly return the graph element's properties.
RETURN TO_JSON(n) AS n;
GRAPH FinGraph
MATCH (n:Account {id: 7})
-- Certain fields in the graph elements, such as TOKENLIST, can't be returned
-- in the TO_JSON function. In those cases, use the SAFE_TO_JSON function instead.
RETURN SAFE_TO_JSON(n) AS n;

Résultat

n
{"identifier":"mUZpbkdyYXBoLkFjY291bnQAeJEO","kind":"node","labels":["Account"],"properties":{"create_time":"2020-01-10T14:22:20.222Z","id":7,"is_blocked":false,"nick_name":"Vacation Fund"}}

Composer des requêtes plus longues avec le mot clé "NEXT"

Vous pouvez associer plusieurs instructions de requête linéaire de graphique à l'aide du mot clé NEXT. L'entrée de la première instruction de requête linéaire est vide. La sortie de chaque instruction de requête linéaire devient l'entrée de l'instruction de requête linéaire suivante.

L'exemple suivant permet de trouver le propriétaire du compte ayant le plus de transferts entrants en enchaînant plusieurs instructions linéaires de graphique. Notez que vous pouvez utiliser la même variable, account dans cet exemple, pour faire référence au même élément de graphique dans plusieurs instructions linéaires.

GRAPH FinGraph
MATCH (:Account)-[:Transfers]->(account:Account)
RETURN account, COUNT(*) AS num_incoming_transfers
GROUP BY account
ORDER BY num_incoming_transfers DESC
LIMIT 1

NEXT

MATCH (account:Account)<-[:Owns]-(owner:Person)
RETURN account.id AS account_id, owner.name AS owner_name, num_incoming_transfers;

Résultat

account_id owner_name num_incoming_transfers
16 Lee 3

Fonctions et expressions

Vous pouvez utiliser toutes les fonctions GoogleSQL (fonctions agrégatives et scalaires), les opérateurs et les expressions conditionnelles dans les requêtes Spanner Graph. Spanner Graph est également compatible avec les fonctions et les opérateurs spécifiques aux graphiques.

Fonctions et opérateurs intégrés

Les fonctions et les opérateurs suivants sont couramment utilisés dans GQL:

  • PROPERTY_EXISTS(n, birthday): indique si n expose la propriété birthday.
  • LABELS(n): renvoie les libellés de n tels que définis dans le schéma du graphique.
  • PROPERTY_NAMES(n): renvoie les noms de propriétés de n.
  • TO_JSON(n): renvoie n au format JSON. Pour en savoir plus, consultez la section concernant la fonction TO_JSON.

La requête suivante illustre le prédicat PROPERTY_EXISTS, la fonction LABELS et la fonction TO_JSON, ainsi que d'autres fonctions intégrées telles que ARRAY_AGG et CONCAT.

GRAPH FinGraph
MATCH (person:Person)-[:Owns]->(account:Account)
RETURN person, ARRAY_AGG(account.nick_name) AS accounts
GROUP BY person

NEXT

RETURN
  LABELS(person) AS labels,
  TO_JSON(person) AS person,
  accounts,
  CONCAT(person.city, ", ", person.country) AS location,
  PROPERTY_EXISTS(person, is_blocked) AS is_blocked_property_exists,
  PROPERTY_EXISTS(person, name) AS name_property_exists
LIMIT 1;

Résultat

is_blocked_property_exists name_property_exists labels comptes emplacement Personne
faux vrai Personne ["Vacation Fund"] Adélaïde, Australie {"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}}

Sous-requêtes

Une sous-requête est une requête imbriquée dans une autre requête. La liste suivante présente les règles de sous-requête de Spanner Graph:

  • Une sous-requête est placée entre accolades {}.
  • Une sous-requête peut commencer par la clause GRAPH initiale pour spécifier le graphique en champ d'application. Le graphique spécifié ne doit pas nécessairement être identique à celui utilisé dans la requête externe.
  • Lorsque la clause GRAPH est omise dans la sous-requête, voici ce qui se passe :
    • Le graphique en champ d'application est inféré à partir du contexte de requête externe le plus proche.
    • La sous-requête doit commencer par une instruction de mise en correspondance de modèle de graphique avec MATCH..
  • Une variable de modèle de graphique déclarée en dehors de la portée de la sous-requête ne peut pas être déclarée à nouveau dans la sous-requête, mais elle peut y être référencée dans des expressions ou des fonctions.

Utiliser une sous-requête pour trouver le nombre total de transferts effectués depuis chaque compte

La requête suivante illustre l'utilisation de la sous-requête VALUE. La sous-requête est placée entre accolades {}, précédées du mot clé VALUE. La requête renvoie le montant total des transferts initiés à partir d'un compte.

GRAPH FinGraph
MATCH (p:Person)-[:Owns]->(account:Account)
RETURN p.name, account.id AS account_id, VALUE {
  MATCH (a:Account)-[transfer:Transfers]->(:Account)
  WHERE a = account
  RETURN SUM(transfer.amount) AS total_transfer
} AS total_transfer;

Résultat

nom account_id total_transfer
Alex 7 400
Dana 20 700
Lee 16 300

Pour obtenir la liste des expressions de sous-requêtes acceptées, consultez Sous-requêtes du graphique Spanner.

Paramètres de requête

Vous pouvez interroger le graphe Spanner avec des paramètres. Pour en savoir plus, consultez la syntaxe et découvrez comment interroger des données avec des paramètres dans les bibliothèques clientes Spanner.

La requête suivante illustre l'utilisation des paramètres de requête.

GRAPH FinGraph
MATCH (person:Person {id: @id})
RETURN person.name;

Interroger des graphiques et des tableaux ensemble

Vous pouvez utiliser des requêtes Graph en conjonction avec SQL pour accéder aux informations de vos graphiques et tableaux simultanément dans une seule instruction.

GRAPH_TABLE

L'opérateur GRAPH_TABLE prend une requête de graphique linéaire et renvoie son résultat sous forme de tableau qui peut être facilement intégré à une requête SQL. Cette interopérabilité vous permet d'enrichir les résultats de requêtes de graphiques avec du contenu non graphique et inversement.

Par exemple, vous pouvez créer un tableau CreditReports et insérer quelques rapports de crédit, comme illustré dans l'exemple suivant:

CREATE TABLE CreditReports (
  person_id     INT64 NOT NULL,
  create_time   TIMESTAMP NOT NULL,
  score         INT64 NOT NULL,
) PRIMARY KEY (person_id, create_time);
INSERT INTO CreditReports (person_id, create_time, score)
VALUES
  (1,"2020-01-10 06:22:20.222", 700),
  (2,"2020-02-10 06:22:20.222", 800),
  (3,"2020-03-10 06:22:20.222", 750);

Identifiez ensuite les personnes d'intérêt à l'aide de la mise en correspondance de modèles de graphiques dans GRAPH_TABLE et joignez les résultats de la requête graphique à la table CreditReports pour accéder au score de crédit.

SELECT
  gt.person.id,
  credit.score AS latest_credit_score
FROM GRAPH_TABLE(
  FinGraph
  MATCH (person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account)
  WHERE account.is_blocked
  RETURN DISTINCT person
) AS gt
JOIN CreditReports AS credit
  ON gt.person.id = credit.person_id
ORDER BY credit.create_time;

Résultat :

person_id latest_credit_score
1 700
2 800

Étape suivante

Découvrez les bonnes pratiques pour optimiser les requêtes.