Praktik terbaik kueri grafik

Dokumen ini menjelaskan praktik terbaik untuk mengoptimalkan kueri Grafik BigQuery.

Mulai penelusuran jalur dari node kardinalitas rendah

Untuk menjaga agar set hasil perantara tetap kecil dan mempercepat eksekusi kueri, tulis kueri grafik Anda sehingga penelusuran jalur dimulai dari node kardinalitas yang lebih rendah, terlepas dari arah penelusuran jalur. Pernyataan MATCH berikut menggunakan filter properti untuk mengurangi jumlah kemungkinan node awal, bukan menghitung semua kecocokan lalu memfilter:

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

Hal ini sangat penting untuk kueri jalur yang dikuantifikasi:

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

Gunakan sintaks ANY atau ANY SHORTEST untuk pemeriksaan konektivitas

Kueri jalur yang dikuantifikasi dapat menampilkan jalur duplikat antara node sumber dan node tujuan. Jika tujuan Anda adalah memeriksa konektivitas dan Anda tidak memerlukan semua kemungkinan jalur, gunakan ANY atau ANY SHORTEST untuk mengurangi komputasi yang berlebihan dan meningkatkan efisiensi pencarian jalur. Misalnya, pernyataan MATCH berikut menggunakan ANY SHORTEST untuk mempertahankan hanya satu jalur di antara setiap pasangan node:

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

Menggunakan penelusuran jalur terarah

Skema Grafik BigQuery bersifat terarah, yang berarti bahwa setiap tepi memiliki node sumber dan node tujuan. Meskipun sintaksis kueri grafik memungkinkan penelusuran jalur ke segala arah (misalnya, -[edge]-), sebaiknya gunakan penelusuran jalur terarah (misalnya, -[edge]-> atau <-[edge]-) untuk performa yang lebih baik. Traversal jalur arah mana pun dapat menyebabkan penurunan performa.

Pernyataan MATCH berikut menggunakan traversal jalur arah mana pun:

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

Sebagai gantinya, gabungkan dua penelusuran terarah dengan UNION ALL:

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

Menentukan label secara eksplisit

Jika label node atau edge tidak disertakan dalam kueri, BigQuery Graph akan mencantumkan semua label node dan edge yang memenuhi syarat. Enumerasi ini dapat menyebabkan lebih banyak label dipindai daripada yang diperlukan. Untuk menghindari hal ini, tentukan label untuk semua node dan tepi dalam kueri Anda jika memungkinkan.

Misalnya, kueri berikut menentukan label Account dan Transfers:

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

Hindari menghilangkan label, karena dapat memindai hubungan lain yang tidak diperlukan antar-node. Dalam kueri berikut, a1 dapat mewakili akun atau orang, dan t dapat mewakili transfer atau kepemilikan akun.

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

Lebih memilih satu pernyataan MATCH

BigQuery Graph memungkinkan Anda menyertakan beberapa pernyataan MATCH dalam satu kueri grafik. Pernyataan ini terhubung oleh variabel yang dideklarasikan beberapa kali yang merepresentasikan node atau tepi yang sama. Namun, penggunaan beberapa pernyataan MATCH dapat mengurangi manfaat kardinalitas di seluruh pernyataan. Jika memungkinkan, gunakan satu pernyataan MATCH untuk mendapatkan performa yang lebih baik.

Misalnya, kueri berikut setara, tetapi kueri pertama berperforma lebih baik karena menggunakan satu pernyataan 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;

Membatasi tepi yang dilalui dari node berkardinalitas tinggi

Saat Anda mengkueri grafik, beberapa node dapat memiliki jumlah tepi masuk atau keluar yang jauh lebih besar dibandingkan dengan node lain. Node dengan kardinalitas tinggi ini terkadang disebut node super atau node hub. Node super dapat menyebabkan masalah performa karena penelusuran melalui node tersebut mungkin melibatkan pemrosesan data dalam jumlah besar, yang menyebabkan kemiringan data dan waktu eksekusi yang lama.

Untuk mengoptimalkan kueri grafik dengan node super, gunakan fungsi ROW_NUMBER() dalam klausa FILTER atau klausa WHERE di MATCH untuk membatasi jumlah tepi yang dilalui kueri dari atau ke node. Teknik ini sangat berguna jika Anda tidak memerlukan enumerasi lengkap semua koneksi dari atau ke super node.

Misalnya, jika beberapa akun di FinGraph memiliki banyak transaksi, Anda dapat menggunakan ROW_NUMBER() untuk membatasi jumlah edge Transfers yang akan dipertimbangkan untuk setiap Account dan menghindari kueri yang tidak efisien:

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;

Contoh node atau edge perantara dalam kueri multi-hop

Anda juga dapat meningkatkan efisiensi kueri dengan menggunakan ROW_NUMBER() untuk mengambil sampel node perantara dalam kueri multi-hop. Teknik ini meningkatkan efisiensi dengan membatasi jumlah jalur yang dipertimbangkan kueri untuk setiap node perantara. Untuk melakukannya, pecah kueri multi-hop menjadi beberapa pernyataan MATCH yang dipisahkan oleh NEXT, dan terapkan ROW_NUMBER() di titik tengah tempat Anda perlu melakukan pengambilan sampel:

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;

Langkah berikutnya