Bonnes pratiques concernant les requêtes de graphe

Ce document décrit les bonnes pratiques à suivre pour optimiser vos requêtes BigQuery Graph.

Commencer la traversée de chemin à partir de nœuds à faible cardinalité

Pour réduire la taille des ensembles de résultats intermédiaires et accélérer l'exécution des requêtes, écrivez vos requêtes de graphe de sorte que la traversée de chemin commence à partir de nœuds à faible cardinalité, quelle que soit la direction de la traversée. Les instructions MATCH suivantes utilisent des filtres de propriété pour réduire le nombre de nœuds de départ possibles au lieu de calculer toutes les correspondances, puis de filtrer :

MATCH (p:Person {id: 10})-[own:Owns]->(a:Account)
MATCH (a:Account WHERE balance > 10)<-[own:Owns]-(p:Person)

Cela est particulièrement important pour les requêtes de chemin quantifiées :

MATCH (p:Person {id: 10})-[own:Owns]->{1,3}(a:Account)

Utiliser la syntaxe ANY ou ANY SHORTEST pour les vérifications de connectivité

Les requêtes de chemin quantifiées peuvent renvoyer des chemins en double entre les nœuds sources et les nœuds de destination. Si votre objectif est de vérifier la connectivité et que vous n'avez pas besoin de tous les chemins possibles, utilisez ANY ou ANY SHORTEST pour réduire les calculs redondants et améliorer l'efficacité de la recherche de chemin. Par exemple, l'instruction MATCH suivante utilise ANY SHORTEST pour ne conserver qu'un seul chemin entre chaque paire de nœuds :

MATCH ANY SHORTEST (a1:Account)-[t:Transfers]->{1,3}(a2:Account)

Utiliser la traversée de chemin directionnelle

Les schémas BigQuery Graph sont directionnels, ce qui signifie que chaque arête comporte un nœud source et un nœud de destination. Bien que la syntaxe des requêtes de graphe autorise la traversée de chemin dans n'importe quelle direction (par exemple, -[edge]-), nous vous recommandons d'utiliser la traversée de chemin directionnelle (par exemple, -[edge]-> ou <-[edge]-) pour de meilleures performances. La traversée de chemin dans n'importe quelle direction peut entraîner une perte de performances.

L'instruction MATCH suivante utilise la traversée de chemin dans n'importe quelle direction :

-- Avoid.
MATCH (a1:Account {id: 7})-[t:Transfers]-(a2:Account)

Combinez plutôt deux traversées directionnelles avec UNION ALL :

MATCH (a1:Account {id: 7})-[t:Transfers]->(a2:Account)
...
UNION ALL
...
MATCH (a1:Account  {id: 7})<-[t:Transfers]-(a2:Account)

Spécifier explicitement les libellés

Si les libellés de nœud ou d'arête sont omis dans une requête, BigQuery Graph énumère tous les libellés de nœud et d'arête éligibles. Cette énumération peut entraîner l'analyse d'un plus grand nombre de libellés que nécessaire. Pour éviter cela, spécifiez les libellés de tous les nœuds et de toutes les arêtes de votre requête dans la mesure du possible.

Par exemple, la requête suivante spécifie les libellés Account et Transfers :

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[t:Transfers]->(a2:Account)
RETURN COUNT(*) AS num_transfers;

Évitez d'omettre des libellés, car cela pourrait entraîner l'analyse d'autres relations inutiles entre les nœuds. Dans la requête suivante, a1 peut représenter un compte ou une personne, et t peut représenter un transfert ou la propriété d'un compte.

GRAPH graph_db.FinGraph
MATCH (a1)-[t]->(a2)
RETURN COUNT(*) AS num_transfers;

Privilégier une seule instruction MATCH

BigQuery Graph vous permet d'inclure plusieurs instructions MATCH dans une seule requête de graphe. Ces instructions sont connectées par des variables multi-déclarées qui représentent le même nœud ou la même arête. Toutefois, l'utilisation de plusieurs instructions MATCH peut réduire les avantages de la cardinalité entre les instructions. Dans la mesure du possible, utilisez une seule instruction MATCH pour de meilleures performances.

Par exemple, les requêtes suivantes sont équivalentes, mais la première est plus performante, car elle utilise une seule instruction MATCH :

-- Preferred syntax.
GRAPH graph_db.FinGraph
MATCH
  (p:Person {id: 1})-[o:Owns]->
  (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
-- Avoid this syntax.
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})-[o:Owns]->(a:Account)
MATCH (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;

Limiter les arêtes traversées à partir de nœuds à cardinalité élevée

Lorsque vous interrogez des graphes, certains nœuds peuvent avoir un nombre d'arêtes entrantes ou sortantes beaucoup plus important que d'autres. Ces nœuds à cardinalité élevée sont parfois appelés super-nœuds ou nœuds hub. Les super-nœuds peuvent entraîner des problèmes de performances, car les traversées peuvent impliquer le traitement de grandes quantités de données, ce qui entraîne une asymétrie des données et des temps d'exécution longs.

Pour optimiser une requête de graphe avec des super-nœuds, utilisez la ROW_NUMBER() fonction dans une FILTER clause ou WHERE clause dans MATCH afin de limiter le nombre d’arêtes que la requête traverse à partir d’un nœud ou vers un nœud. Cette technique est particulièrement utile lorsque vous n'avez pas besoin d'une énumération complète de toutes les connexions à partir d'un super-nœud ou vers un super-nœud.

Par exemple, si certains comptes de FinGraph comportent un grand nombre de transactions, vous pouvez utiliser ROW_NUMBER() pour limiter le nombre d'arêtes Transfers à prendre en compte pour chaque Account et éviter une requête inefficace :

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers WHERE e1 IN {
  GRAPH graph_db.FinGraph
  -- Sample 5 edges per source node
  MATCH -[selected_e:Transfers]->
    FILTER ROW_NUMBER() OVER (
      PARTITION BY SOURCE_NODE_ID(selected_e)) < 5
    RETURN selected_e
}]->{1,3}(a2:Account)
RETURN COUNT(*) AS cnt;

Échantillonner les nœuds ou les arêtes intermédiaires dans les requêtes multi-sauts

Vous pouvez également améliorer l'efficacité des requêtes en utilisant ROW_NUMBER() pour échantillonner les nœuds intermédiaires dans les requêtes multi-sauts. Cette technique améliore l'efficacité en limitant le nombre de chemins que la requête prend en compte pour chaque nœud intermédiaire. Pour ce faire, divisez une requête multi-sauts en plusieurs instructions MATCH séparées par NEXT, puis appliquez ROW_NUMBER() au point médian où vous devez échantillonner :

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers]->(a2:Account)
-- Sample 5 destination nodes per a1 source node
FILTER ROW_NUMBER() OVER (PARTITION BY ELEMENT_ID(a1)) < 5
RETURN a1, a2
NEXT
MATCH (a2)-[e2:Transfers]->(a3:Account)
RETURN a1.id AS src_id, a2.id AS mid_id, a3.id AS dst_id;

Étape suivante