Praktik terbaik untuk mendesain skema Grafik Spanner

Dokumen ini menjelaskan praktik terbaik untuk mendesain skema Spanner Graph, dengan berfokus pada kueri yang efisien, penelusuran edge yang dioptimalkan, dan teknik pengelolaan data yang efektif.

Untuk mengetahui informasi tentang desain skema Spanner (bukan skema Spanner Graph), lihat Praktik terbaik desain skema.

Memilih desain skema

Desain skema Anda memengaruhi performa grafik. Topik berikut akan membantu Anda memilih strategi yang efektif.

Desain yang memiliki skema versus desain tanpa skema

  • Desain skematis menyimpan definisi grafik dalam skema Spanner Graph, yang cocok untuk grafik stabil dengan perubahan definisi yang jarang terjadi. Skema menerapkan definisi grafik, dan properti mendukung semua jenis data Spanner.

  • Desain tanpa skema menyimpulkan definisi grafik dari data, sehingga menawarkan lebih banyak fleksibilitas tanpa memerlukan perubahan skema. Label dan properti dinamis tidak diterapkan secara default. Properti harus berupa nilai JSON yang valid.

Berikut adalah ringkasan perbedaan utama antara pengelolaan data dengan skema dan tanpa skema. Selain itu, pertimbangkan kueri grafik Anda untuk membantu memutuskan jenis skema yang akan digunakan.

Fitur Pengelolaan data yang dischematisasi Pengelolaan data tanpa skema
Menyimpan definisi grafik Definisi grafik disimpan dalam skema Spanner Graph. Definisi grafik terlihat jelas dari data. Namun, Spanner Graph tidak memeriksa data untuk menyimpulkan definisi.
Memperbarui definisi grafik Memerlukan perubahan skema Spanner Graph. Cocok jika definisi sudah jelas dan jarang berubah. Tidak diperlukan perubahan skema Spanner Graph.
Menerapkan definisi grafik Skema grafik properti menerapkan jenis node yang diizinkan untuk sebuah edge. Selain itu, library ini juga menerapkan properti dan jenis properti yang diizinkan dari jenis node atau tepi grafik. Tidak diterapkan secara default. Anda dapat menggunakan batasan pemeriksaan untuk menerapkan integritas data label dan properti.
Jenis data properti Mendukung semua jenis data Spanner, misalnya, timestamp. Properti dinamis harus berupa nilai JSON yang valid.

Memilih desain skema berdasarkan kueri grafik

Desain skema dan tanpa skema sering kali menawarkan performa yang sebanding. Namun, saat kueri menggunakan pola jalur yang dikuantifikasi yang mencakup beberapa jenis node atau edge, desain tanpa skema menawarkan performa yang lebih baik.

Model data yang mendasarinya adalah alasan utama untuk hal ini. Desain tanpa skema menyimpan semua data dalam tabel node dan edge tunggal, yang DYNAMIC LABEL diterapkan. Kueri yang melintasi beberapa jenis dijalankan dengan pemindaian tabel minimal.

Sebaliknya, desain skematis biasanya menggunakan tabel terpisah untuk setiap jenis node dan edge, sehingga kueri yang mencakup beberapa jenis harus memindai dan menggabungkan data dari semua tabel yang sesuai.

Berikut adalah contoh kueri yang berfungsi baik dengan desain tanpa skema, dan contoh kueri yang berfungsi baik dengan kedua desain:

Desain tanpa skema

Kueri berikut berperforma lebih baik dengan desain tanpa skema karena menggunakan pola jalur yang dikuantifikasi yang dapat mencocokkan beberapa jenis node dan tepi:

  • Pola jalur terkuantifikasi kueri ini menggunakan beberapa jenis tepi (Transfer atau Withdraw) dan tidak menentukan jenis node perantara untuk jalur yang lebih panjang dari satu hop.

    GRAPH FinGraph
    MATCH p = (:Account {id:1})-[:Transfer|Withdraw]->{1,3}(:Account)
    RETURN TO_JSON(p) AS p;
    
  • Pola jalur terkuantifikasi kueri ini menemukan jalur satu hingga tiga hop antara node Person dan Account, menggunakan beberapa jenis tepi (Owns atau Transfers), tanpa menentukan jenis node perantara untuk jalur yang lebih panjang. Hal ini memungkinkan jalur melintasi node perantara dari berbagai jenis. Misalnya, (:Person)-[:Owns]->(:Account)-[:Transfers]->(:Account).

    GRAPH FinGraph
    MATCH p = (:Person {id:1})-[:Owns|Transfers]->{1,3}(:Account)
    RETURN TO_JSON(p) AS p;
    
  • Pola jalur terkuantifikasi kueri ini menemukan jalur dengan satu hingga tiga lompatan antara node Person dan Account, tanpa menentukan label tepi. Mirip dengan kueri sebelumnya, kueri ini memungkinkan jalur melintasi node perantara dari berbagai jenis.

    GRAPH FinGraph
    MATCH p = (:Person {id:1})-[]->{1,3}(:Account)
    RETURN TO_JSON(p) AS p;
    
  • Kueri ini menemukan jalur satu hingga tiga hop antara node Account menggunakan tepi jenis Owns ke segala arah (-[:Owns]-). Karena jalur dapat melintasi tepi ke segala arah dan node perantara tidak ditentukan, jalur dua hop dapat melewati node dari berbagai jenis. Misalnya, (:Account)-[:Owns]-(:Person)-[:Owns]-(:Account).

    GRAPH FinGraph
    MATCH p = (:Account {id:1})-[:Owns]-{1,3}(:Account)
    RETURN TO_JSON(p) AS p;
    

Kedua desain

Kueri berikut memiliki performa yang sebanding dengan desain yang memiliki skema dan tanpa skema. Jalur terkuantifikasinya, (:Account)-[:Transfer]->{1,3}(:Account), melibatkan satu jenis node, Account, dan satu jenis tepi, Transfer. Karena jalur hanya melibatkan satu jenis node dan satu jenis tepi, performa kedua desain dapat dibandingkan. Meskipun node perantara tidak diberi label secara eksplisit, pola membatasi node tersebut menjadi node Account. Node Person muncul di luar jalur terkuantifikasi ini.

GRAPH FinGraph
MATCH p = (:Person {id:1})-[:Owns]->(:Account)-[:Transfer]->{1,3}(:Account)
RETURN TO_JSON(p) AS p;

Mengoptimalkan performa skema Spanner Graph

Setelah memilih untuk menggunakan skema Spanner Graph yang memiliki skema atau tidak memiliki skema, Anda dapat mengoptimalkan performanya dengan cara berikut:

Mengoptimalkan penelusuran tepi

Penelusuran tepi adalah proses menavigasi grafik dengan mengikuti tepinya, dimulai dari node tertentu dan bergerak di sepanjang tepi yang terhubung untuk mencapai node lain. Skema menentukan arah tepi. Penelusuran tepi adalah operasi mendasar dalam Spanner Graph, sehingga peningkatan efisiensi penelusuran tepi dapat meningkatkan performa aplikasi Anda secara signifikan.

Anda dapat melintasi tepi dalam dua arah:

  • Penelusuran tepi penerusan mengikuti tepi keluar dari node sumber.
  • Traversal tepi terbalik mengikuti tepi masuk dari node tujuan.

Contoh kueri penelusuran tepi maju dan mundur

Contoh kueri berikut melakukan penelusuran tepi maju dari tepi Owns untuk orang tertentu:

GRAPH FinGraph
MATCH (person:Person {id: 1})-[owns:Owns]->(accnt:Account)
RETURN accnt.id;

Contoh kueri berikut melakukan penelusuran sisi terbalik dari sisi Owns untuk akun tertentu:

GRAPH FinGraph
MATCH (accnt:Account {id: 1})<-[owns:Owns]-(person:Person)
RETURN person.name;

Mengoptimalkan traversal tepi penerusan

Untuk meningkatkan performa traversal edge penerusan, optimalkan traversal dari sumber ke edge dan dari edge ke tujuan.

  • Untuk mengoptimalkan traversal sumber ke tepi, selang-selingi tabel input tepi ke dalam tabel input node sumber menggunakan klausa INTERLEAVE IN PARENT. Penyisipan adalah teknik pengoptimalan penyimpanan di Spanner yang menempatkan baris tabel turunan bersama dengan baris induk yang sesuai di penyimpanan. Untuk mengetahui informasi selengkapnya tentang penyisipan, lihat Ringkasan skema.

  • Untuk mengoptimalkan penelusuran dari tepi ke tujuan, buat batasan kunci asing antara tepi dan tujuan
    node. Tindakan ini menerapkan batasan edge-to-destination, yang dapat meningkatkan performa dengan menghilangkan pemindaian tabel tujuan. Jika kunci asing yang diterapkan menyebabkan hambatan performa penulisan (misalnya, saat memperbarui node hub), gunakan kunci asing informasional sebagai gantinya.

Contoh berikut menunjukkan cara menggunakan penyisipan dengan batasan kunci asing yang diterapkan dan informatif.

Kunci asing yang diterapkan

Dalam contoh tabel tepi ini, PersonOwnAccount melakukan hal berikut:

  • Menyisipkan ke dalam tabel node sumber Person.

  • Membuat kunci asing yang diterapkan ke tabel node tujuan Account.

CREATE TABLE Person (
  id               INT64 NOT NULL,
  name             STRING(MAX),
) PRIMARY KEY (id);

CREATE TABLE Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
  close_time       TIMESTAMP,
) PRIMARY KEY (id)

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id)
    REFERENCES Account (id)
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

Kunci asing informasi

Dalam contoh tabel tepi ini, PersonOwnAccount melakukan hal berikut:

  • Menyisipkan ke dalam tabel node sumber Person.

  • Membuat kunci asing informasi ke tabel node tujuan Account.

CREATE TABLE Person (
  id               INT64 NOT NULL,
  name             STRING(MAX),
) PRIMARY KEY (id);

CREATE TABLE Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
  close_time       TIMESTAMP,
) PRIMARY KEY (id)

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id)
    REFERENCES Account (id) NOT ENFORCED
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

Mengoptimalkan penelusuran tepi terbalik

Optimalkan traversal sisi berlawanan kecuali kueri Anda hanya menggunakan traversal sisi maju, karena kueri yang melibatkan traversal sisi berlawanan atau dua arah sering terjadi.

Untuk mengoptimalkan penelusuran tepi terbalik, Anda dapat melakukan hal berikut:

  • Buat indeks sekunder pada tabel edge.

  • Selang-selingi indeks ke dalam tabel input node tujuan untuk menempatkan tepi bersama dengan node tujuan.

  • Simpan properti tepi dalam indeks.

Contoh ini menunjukkan indeks sekunder untuk mengoptimalkan penelusuran sisi terbalik untuk tabel sisi PersonOwnAccount:

  • Klausul INTERLEAVE IN mengalokasikan data indeks dengan tabel node tujuan Account.

  • Klausul STORING menyimpan properti edge dalam indeks.

Untuk mengetahui informasi selengkapnya tentang indeks penyisipan, lihat Indeks dan penyisipan.

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

CREATE INDEX AccountOwnedByPerson
ON PersonOwnAccount (account_id)
STORING (create_time),
INTERLEAVE IN Account;

Menggunakan indeks sekunder untuk memfilter properti

Indeks sekunder memungkinkan pencarian node dan tepi yang efisien berdasarkan nilai properti tertentu. Menggunakan indeks membantu menghindari pemindaian seluruh tabel dan sangat berguna untuk grafik besar.

Mempercepat pemfilteran node menurut properti

Kueri berikut yang menemukan akun untuk nama panggilan tertentu. Karena tidak menggunakan indeks sekunder, semua node Account harus dipindai untuk menemukan hasil yang cocok:

GRAPH FinGraph
MATCH (acct:Account)
WHERE acct.nick_name = "abcd"
RETURN acct.id;

Buat indeks sekunder pada properti yang difilter dalam skema Anda untuk mempercepat proses pemfilteran:

CREATE TABLE Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
  is_blocked       BOOL,
  nick_name        STRING(MAX),
) PRIMARY KEY (id);

CREATE INDEX AccountByNickName
ON Account (nick_name);

Mempercepat pemfilteran tepi menurut properti

Anda dapat menggunakan indeks sekunder untuk meningkatkan performa pemfilteran tepi berdasarkan nilai properti.

Traversal tepi depan

Tanpa indeks sekunder, kueri ini harus memindai semua edge seseorang untuk menemukan edge yang cocok dengan filter create_time:

GRAPH FinGraph
MATCH (person:Person)-[owns:Owns]->(acct:Account)
WHERE person.id = 1
  AND owns.create_time >= PARSE_TIMESTAMP("%c", "Thu Dec 25 07:30:00 2008")
RETURN acct.id;

Kode berikut meningkatkan efisiensi kueri dengan membuat indeks sekunder pada referensi node sumber edge (id) dan properti edge (create_time). Kueri juga menentukan indeks sebagai turunan yang disisipkan dari tabel input node sumber, yang mengalokasikan indeks dengan node sumber.

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

CREATE INDEX PersonOwnAccountByCreateTime
ON PersonOwnAccount (id, create_time)
INTERLEAVE IN Person;

Traversal tepi terbalik

Tanpa indeks sekunder, kueri penelusuran sisi terbalik berikut harus membaca semua sisi sebelum dapat menemukan orang yang memiliki akun yang ditentukan setelah create_time yang ditentukan:

GRAPH FinGraph
MATCH (acct:Account)<-[owns:Owns]-(person:Person)
WHERE acct.id = 1
  AND owns.create_time >= PARSE_TIMESTAMP("%c", "Thu Dec 25 07:30:00 2008")
RETURN person.id;

Kode berikut meningkatkan efisiensi kueri dengan membuat indeks sekunder pada referensi node tujuan edge (account_id) dan properti edge (create_time). Kueri juga menentukan indeks sebagai turunan yang disisipkan dari tabel node tujuan, yang menempatkan indeks bersama dengan node tujuan.

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

CREATE INDEX AccountOwnedByPersonByCreateTime
ON PersonOwnAccount (account_id, create_time),
INTERLEAVE IN Account;

Mencegah tepi yang menggantung

Edge yang menghubungkan nol atau satu node, dangling edge, dapat mengganggu efisiensi kueri Spanner Graph dan integritas struktur grafik. Tepi yang tidak terhubung dapat terjadi jika Anda menghapus node tanpa menghapus tepi yang terkait. Tepi yang tidak terhubung juga dapat terjadi jika Anda membuat tepi, tetapi node sumber atau tujuannya tidak ada. Untuk mencegah ujung yang tidak terhubung, gabungkan berikut ini dalam skema Spanner Graph Anda:

Menggunakan batasan referensial

Anda dapat menggunakan penyisipan dan kunci asing yang diterapkan di kedua endpoint untuk mencegah tepi yang tidak terhubung dengan mengikuti langkah-langkah berikut:

  1. Selang-selingkan tabel input tepi ke dalam tabel input node sumber untuk memastikan bahwa node sumber tepi selalu ada.

  2. Buat batasan kunci asing yang diterapkan pada edge untuk memastikan bahwa node tujuan edge selalu ada. Meskipun kunci asing yang diterapkan mencegah tepi yang tidak terhubung, kunci asing tersebut membuat penyisipan dan penghapusan tepi menjadi lebih mahal.

Contoh berikut menggunakan kunci asing yang diterapkan dan menyisipkan tabel input edge ke dalam tabel input node sumber menggunakan klausa INTERLEAVE IN PARENT. Bersama-sama, penggunaan kunci asing yang diterapkan dan interleaving juga dapat membantu mengoptimalkan traversal tepi maju.

  CREATE TABLE PersonOwnAccount (
    id               INT64 NOT NULL,
    account_id       INT64 NOT NULL,
    create_time      TIMESTAMP,
    CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id) ON DELETE CASCADE,
  ) PRIMARY KEY (id, account_id),
    INTERLEAVE IN PARENT Person ON DELETE CASCADE;

Menghapus tepi dengan ON DELETE CASCADE

Saat Anda menggunakan penyisipan atau kunci asing yang diterapkan untuk mencegah ujung yang tidak terhubung, gunakan klausa ON DELETE CASCADE dalam skema Spanner Graph untuk menghapus tepi terkait node dalam transaksi yang sama yang menghapus node. Untuk mengetahui informasi selengkapnya, lihat Menghapus secara bertingkat untuk tabel yang disisipkan dan Tindakan kunci asing.

Cascade penghapusan untuk tepi yang menghubungkan berbagai jenis node

Contoh berikut menunjukkan cara menggunakan ON DELETE CASCADE dalam skema Spanner Graph untuk menghapus edge yang tidak terhubung saat Anda menghapus node sumber atau tujuan. Dalam kedua kasus tersebut, jenis node yang dihapus dan jenis node yang terhubung ke node tersebut melalui tepi berbeda.

Node sumber

Gunakan penyisipan untuk menghapus tepi yang tidak terhubung saat node sumber dihapus. Berikut cara menggunakan penyisipan untuk menghapus tepi keluar saat node sumber (Person) dihapus. Untuk mengetahui informasi selengkapnya, lihat Membuat tabel interleaved.

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id) ON DELETE CASCADE,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE

Node tujuan

Gunakan batasan kunci asing untuk menghapus tepi yang tidak terhubung saat node tujuan dihapus. Contoh berikut menunjukkan cara menggunakan kunci asing dengan ON DELETE CASCADE dalam tabel edge untuk menghapus edge masuk saat node tujuan (Account) dihapus:

CONSTRAINT FK_Account FOREIGN KEY(account_id)
  REFERENCES Account(id) ON DELETE CASCADE

Cascade penghapusan untuk tepi yang menghubungkan jenis node yang sama

Jika node sumber dan tujuan tepi memiliki jenis yang sama dan tepi disisipkan ke dalam node sumber, Anda dapat menentukan ON DELETE CASCADE untuk node sumber atau tujuan, tetapi tidak keduanya.

Untuk mencegah tepi yang menggantung dalam skenario ini, jangan selang-seling ke dalam tabel input node sumber. Sebagai gantinya, buat dua kunci asing yang diterapkan pada referensi node sumber dan tujuan.

Contoh berikut menggunakan AccountTransferAccount sebagai tabel input tepi. Tindakan ini menentukan dua kunci asing, satu di setiap node ujung transfer edge, keduanya dengan tindakan ON DELETE CASCADE.

CREATE TABLE AccountTransferAccount (
  id               INT64 NOT NULL,
  to_id            INT64 NOT NULL,
  amount           FLOAT64,
  create_time      TIMESTAMP NOT NULL,
  order_number     STRING(MAX),
  CONSTRAINT FK_FromAccount FOREIGN KEY (id) REFERENCES Account (id) ON DELETE CASCADE,
  CONSTRAINT FK_ToAccount FOREIGN KEY (to_id) REFERENCES Account (id) ON DELETE CASCADE,
) PRIMARY KEY (id, to_id);

Mengonfigurasi time to live (TTL) pada node dan tepi

TTL memungkinkan Anda menghapus data setelah jangka waktu yang ditentukan. Anda dapat menggunakan TTL dalam skema untuk mempertahankan ukuran dan performa database dengan menghapus data yang memiliki masa berlaku atau relevansi terbatas. Misalnya, Anda dapat mengonfigurasinya untuk menghapus informasi sesi, cache sementara, atau log peristiwa.

Contoh berikut menggunakan TTL untuk menghapus akun 90 hari setelah penutupannya:

  CREATE TABLE Account (
    id               INT64 NOT NULL,
    create_time      TIMESTAMP,
    close_time       TIMESTAMP,
  ) PRIMARY KEY (id),
    ROW DELETION POLICY (OLDER_THAN(close_time, INTERVAL 90 DAY));

Saat menentukan kebijakan TTL pada tabel node, Anda harus mengonfigurasi cara penanganan edge terkait untuk mencegah edge yang tidak diinginkan:

  • Untuk tabel tepi yang disisipkan: Jika tabel tepi disisipkan dalam tabel node, Anda dapat menentukan hubungan penyisipan dengan ON DELETE CASCADE. Hal ini memastikan bahwa saat TTL menghapus node, tepi yang saling terkait juga dihapus.

  • Untuk tabel edge dengan kunci asing: Jika tabel edge mereferensikan tabel node dengan kunci asing, Anda memiliki dua opsi:

    • Untuk menghapus tepi secara otomatis saat node yang dirujuk dihapus oleh TTL, gunakan ON DELETE CASCADE pada kunci asing. Tindakan ini mempertahankan integritas referensial.
    • Untuk mengizinkan tepi tetap ada setelah node yang dirujuk dihapus (membuat tepi yang tidak terhubung), tentukan kunci asing sebagai kunci asing informasi.

Dalam contoh berikut, tabel edge AccountTransferAccount tunduk pada dua kebijakan penghapusan data:

  • Kebijakan TTL menghapus catatan transfer yang sudah lebih dari sepuluh tahun.
  • Klausul ON DELETE CASCADE menghapus semua catatan transfer yang terkait dengan sumber saat akun tersebut dihapus.
CREATE TABLE AccountTransferAccount (
  id               INT64 NOT NULL,
  to_id            INT64 NOT NULL,
  amount           FLOAT64,
  create_time      TIMESTAMP NOT NULL,
  order_number     STRING(MAX),
) PRIMARY KEY (id, to_id),
  INTERLEAVE IN PARENT Account ON DELETE CASCADE,
  ROW DELETION POLICY (OLDER_THAN(create_time, INTERVAL 3650 DAY));

Menggabungkan tabel input node dan edge

Untuk mengoptimalkan skema, tentukan node dan tepi masuk atau keluarnya dalam satu tabel. Pendekatan ini memberikan manfaat sebagai berikut:

  • Lebih sedikit tabel: Mengurangi jumlah tabel dalam skema Anda, yang menyederhanakan pengelolaan data.

  • Peningkatan performa kueri: Menghilangkan penelusuran yang menggunakan gabungan ke tabel edge terpisah.

Teknik ini berfungsi dengan baik saat kunci utama tabel juga menentukan hubungan dengan tabel lain. Misalnya, jika tabel Account memiliki kunci utama gabungan (owner_id, account_id), bagian owner_id dapat berupa kunci asing yang mereferensikan tabel Person. Struktur ini memungkinkan tabel Account untuk merepresentasikan node Account dan tepi masuk dari node Person.

  CREATE TABLE Person (
    id INT64 NOT NULL,
  ) PRIMARY KEY (id);

  -- Assume each account has exactly one owner.
  CREATE TABLE Account (
    owner_id INT64 NOT NULL,
    account_id INT64 NOT NULL,
  ) PRIMARY KEY (owner_id, account_id);

Anda dapat menggunakan tabel Account untuk menentukan node Account dan tepi Owns masuknya. Hal ini ditunjukkan dalam pernyataan CREATE PROPERTY GRAPH berikut. Dalam klausa EDGE TABLES, Anda memberikan alias Owns untuk tabel Account. Hal ini karena setiap elemen dalam skema grafik harus memiliki nama yang unik.

  CREATE PROPERTY GRAPH FinGraph
    NODE TABLES (
      Person,
      Account
    )
    EDGE TABLES (
      Account AS Owns
        SOURCE KEY (owner_id) REFERENCES Person
        DESTINATION KEY (owner_id, account_id) REFERENCES Account
    );

Langkah berikutnya