Best Practices für Graph-Abfragen

In diesem Dokument werden Best Practices zur Optimierung Ihrer BigQuery Graph-Abfragen beschrieben.

Path Traversal mit Knoten mit niedriger Kardinalität beginnen

Damit Zwischenergebnismengen klein bleiben und die Ausführung von Abfragen beschleunigt wird, sollten Sie Ihre Graphabfragen so schreiben, dass die Pfadsuche unabhängig von der Richtung des Pfads von Knoten mit niedriger Kardinalität aus beginnt. In den folgenden MATCH-Anweisungen werden Attributfilter verwendet, um die Anzahl der möglichen Startknoten zu reduzieren, anstatt alle Übereinstimmungen zu berechnen und dann zu filtern:

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

Das ist besonders wichtig für quantifizierte Pfadabfragen:

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

ANY- oder ANY SHORTEST-Syntax für Konnektivitätsprüfungen verwenden

Bei quantifizierten Pfadabfragen können doppelte Pfade zwischen Quell- und Zielknoten zurückgegeben werden. Wenn Sie nur die Konnektivität prüfen möchten und nicht alle möglichen Pfade benötigen, verwenden Sie ANY oder ANY SHORTEST, um redundante Berechnungen zu reduzieren und die Effizienz der Pfadsuche zu verbessern. In der folgenden MATCH-Anweisung wird beispielsweise ANY SHORTEST verwendet, um nur einen Pfad zwischen jedem Knotenpaar beizubehalten:

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

Path Traversal verwenden

BigQuery-Grafikschemata sind gerichtet. Das bedeutet, dass jede Kante einen Quellknoten und einen Zielknoten hat. Obwohl die Syntax für Grafabfragen die Pfadnavigation in beliebiger Richtung zulässt (z. B. -[edge]-), empfehlen wir für eine bessere Leistung die gerichtete Pfadnavigation (z. B. -[edge]-> oder <-[edge]-). Die Pfadnavigation in beliebiger Richtung kann zu Leistungseinbußen führen.

Die folgende MATCH-Anweisung verwendet die Path Traversal in beliebiger Richtung:

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

Kombinieren Sie stattdessen zwei Richtungsdurchläufe mit UNION ALL:

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

Labels explizit angeben

Wenn Knoten- oder Kantenlabels in einer Abfrage weggelassen werden, listet BigQuery Graph alle infrage kommenden Knoten- und Kantenlabels auf. Diese Aufzählung kann dazu führen, dass mehr Labels als nötig gescannt werden. Um dies zu vermeiden, sollten Sie nach Möglichkeit Labels für alle Knoten und Kanten in Ihrer Abfrage angeben.

In der folgenden Abfrage werden beispielsweise die Labels Account und Transfers angegeben:

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

Lassen Sie keine Labels aus, da sonst möglicherweise andere unnötige Beziehungen zwischen Knoten gescannt werden. In der folgenden Abfrage kann a1 ein Konto oder eine Person und t eine Übertragung oder ein Konto-Inhaber sein.

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

Einzelne MATCH-Anweisung bevorzugen

Mit BigQuery Graph können Sie mehrere MATCH-Anweisungen in eine einzelne Graphabfrage einfügen. Diese Anweisungen sind durch mehrfach deklarierte Variablen verbunden, die denselben Knoten oder dieselbe Kante darstellen. Die Verwendung mehrerer MATCH-Anweisungen kann jedoch die Vorteile der Kardinalität über Anweisungen hinweg verringern. Verwenden Sie nach Möglichkeit eine einzelne MATCH-Anweisung, um eine bessere Leistung zu erzielen.

Die folgenden Abfragen sind beispielsweise gleichwertig, aber die erste bietet eine bessere Leistung, da sie eine einzelne MATCH-Anweisung verwendet:

-- 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;

Anzahl der durchlaufenen Kanten von Knoten mit hoher Kardinalität begrenzen

Wenn Sie Diagramme abfragen, kann es vorkommen, dass einige Knoten im Vergleich zu anderen Knoten eine deutlich größere Anzahl von eingehenden oder ausgehenden Kanten haben. Diese Knoten mit hoher Kardinalität werden manchmal als Superknoten oder Hub-Knoten bezeichnet. Superknoten können Leistungsprobleme verursachen, da bei Traversierungen durch sie möglicherweise große Datenmengen verarbeitet werden müssen, was zu Datenverzerrungen und langen Ausführungszeiten führt.

Um eine Abfrage eines Graphen mit Superknoten zu optimieren, verwenden Sie die ROW_NUMBER()-Funktion in einer FILTER- oder WHERE-Klausel in MATCH, um die Anzahl der Kanten zu begrenzen, die die Abfrage von oder zu einem Knoten durchläuft. Diese Methode ist besonders nützlich, wenn Sie keine vollständige Auflistung aller Verbindungen von oder zu einem Superknoten benötigen.

Wenn beispielsweise einige Konten in FinGraph eine große Anzahl von Transaktionen haben, können Sie mit ROW_NUMBER() die Anzahl der Transfers-Kanten begrenzen, die für jede Account berücksichtigt werden sollen, um eine ineffiziente Abfrage zu vermeiden:

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;

Zwischenknoten oder ‑kanten in Multi-Hop-Abfragen auswählen

Sie können die Effizienz von Abfragen auch verbessern, indem Sie ROW_NUMBER() verwenden, um Zwischenknoten in Multi-Hop-Abfragen zu testen. Diese Technik verbessert die Effizienz, indem die Anzahl der Pfade begrenzt wird, die die Abfrage für jeden Zwischenknoten berücksichtigt. Dazu müssen Sie eine Multi-Hop-Abfrage in mehrere MATCH-Anweisungen aufteilen, die durch NEXT getrennt sind, und ROW_NUMBER() in der Mitte anwenden, an der Sie testen müssen:

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;

Nächste Schritte