Relasi

Arah dan tipe relasi sebagai koneksi tersimpan yang membuat penelusuran graf murah.

Daftar isi

Topik ini membahas relasi (relationship) sebagai komponen penghubung pada model property graph Neo4j. Lingkupnya mencakup arah dan tipe pada setiap relasi, penyimpanan relasi sebagai koneksi kelas satu yang membuat penelusuran (traversal) murah, pembacaan arah dalam pola Cypher, penelusuran tanpa peduli arah, serta tipe relasi sebagai kontrak makna. Data contoh tetap menggunakan ranah perpustakaan pada modul ini. Setelah membacanya, relasi dapat dituliskan dalam pola Cypher dengan arah yang benar dan tipe yang tepat.

Arah dan tipe pada setiap relasi#

Setiap relasi menghubungkan dua node dan menyimpan dua informasi struktural, yaitu arah dari node awal menuju node akhir serta satu tipe yang menyatakan makna hubungannya. Tipe ditulis dengan huruf kapital dan pemisah garis bawah mengikuti rekomendasi dokumentasi Neo4j, misalnya MENULIS dan MEMINJAM. Arah dan tipe bukan anotasi yang dihitung saat kueri berjalan, melainkan bagian dari data yang tersimpan.

Data contoh menggunakan dua tipe relasi, yaitu :MENULIS dari :Penulis menuju :Buku dan :MEMINJAM dari :Anggota menuju :Buku. Skrip penyiapan berikut membangun node dan relasinya dengan MERGE, yakni pencocokan pola sebelum pembuatan, sehingga skrip idempoten dan dapat dijalankan berulang tanpa menimbulkan relasi ganda. Properti tanggal pada :MEMINJAM diisi dengan nilai tanggal statis. Pernyataan yang hanya menulis tidak mencetak keluaran, sehingga skrip ditutup dengan kueri yang menampilkan seluruh relasi menurut kolom dari, tipe, dan ke.

cypher
MERGE (b:Buku {isbn: "978-0-00-000001-3"})
  SET b.judul = "Catatan Pengelana", b.tahunTerbit = 2019;
MERGE (b:Buku {isbn: "978-0-00-000002-0"})
  SET b.judul = "Rumah Pena", b.tahunTerbit = 2021;
MERGE (b:Buku {isbn: "978-0-00-000003-8"})
  SET b.judul = "Anak Muara", b.tahunTerbit = 2020;
MERGE (b:Buku {isbn: "978-0-00-000004-5"})
  SET b.judul = "Peta Angin", b.tahunTerbit = 2022;
MERGE (b:Buku {isbn: "978-0-00-000005-2"})
  SET b.judul = "Jejak Basirah", b.tahunTerbit = 2023;
MERGE (a:Anggota {nomorAnggota: 1}) SET a.nama = "Sari";
MERGE (a:Anggota {nomorAnggota: 2}) SET a.nama = "Tono";
MERGE (a:Anggota {nomorAnggota: 3}) SET a.nama = "Rina";
MERGE (a:Anggota {nomorAnggota: 4}) SET a.nama = "Wawan";
MERGE (p:Penulis {nama: "Nurul Widyastuti"});
MERGE (p:Penulis {nama: "Agam Prawira"});
MERGE (p:Penulis {nama: "Hana Fadhila"});
MERGE (p:Penulis {nama: "Nurul Widyastuti"})-[:MENULIS]->(b:Buku {isbn: "978-0-00-000001-3"});
MERGE (p:Penulis {nama: "Nurul Widyastuti"})-[:MENULIS]->(b:Buku {isbn: "978-0-00-000003-8"});
MERGE (p:Penulis {nama: "Agam Prawira"})-[:MENULIS]->(b:Buku {isbn: "978-0-00-000002-0"});
MERGE (p:Penulis {nama: "Agam Prawira"})-[:MENULIS]->(b:Buku {isbn: "978-0-00-000005-2"});
MERGE (p:Penulis {nama: "Hana Fadhila"})-[:MENULIS]->(b:Buku {isbn: "978-0-00-000003-8"});
MERGE (p:Penulis {nama: "Hana Fadhila"})-[:MENULIS]->(b:Buku {isbn: "978-0-00-000004-5"});
MERGE (a:Anggota {nomorAnggota: 1})-[r:MEMINJAM]->(b:Buku {isbn: "978-0-00-000001-3"})
  SET r.tanggal = date("2026-09-01");
MERGE (a:Anggota {nomorAnggota: 2})-[r:MEMINJAM]->(b:Buku {isbn: "978-0-00-000002-0"})
  SET r.tanggal = date("2026-09-05");
MERGE (a:Anggota {nomorAnggota: 3})-[r:MEMINJAM]->(b:Buku {isbn: "978-0-00-000003-8"})
  SET r.tanggal = date("2026-09-12");
MERGE (a:Anggota {nomorAnggota: 1})-[r:MEMINJAM]->(b:Buku {isbn: "978-0-00-000004-5"})
  SET r.tanggal = date("2026-09-20");
MERGE (a:Anggota {nomorAnggota: 4})-[r:MEMINJAM]->(b:Buku {isbn: "978-0-00-000005-2"})
  SET r.tanggal = date("2026-09-25");
MATCH (n:Anggota|Penulis)-[r:MENULIS|MEMINJAM]->(b:Buku)
RETURN n.nama AS dari, type(r) AS tipe, b.judul AS ke
ORDER BY tipe, dari, ke
text Keluaran
dari, tipe, ke
"Rina", "MEMINJAM", "Anak Muara"
"Sari", "MEMINJAM", "Catatan Pengelana"
"Sari", "MEMINJAM", "Peta Angin"
"Tono", "MEMINJAM", "Rumah Pena"
"Wawan", "MEMINJAM", "Jejak Basirah"
"Agam Prawira", "MENULIS", "Jejak Basirah"
"Agam Prawira", "MENULIS", "Rumah Pena"
"Hana Fadhila", "MENULIS", "Anak Muara"
"Hana Fadhila", "MENULIS", "Peta Angin"
"Nurul Widyastuti", "MENULIS", "Anak Muara"
"Nurul Widyastuti", "MENULIS", "Catatan Pengelana"

Penyimpanan relasi sebagai koneksi kelas satu#

Neo4j menyimpan relasi sebagai koneksi fisik di samping node yang dihubungkannya, desain yang dikenal dengan istilah index-free adjacency. Setiap node menyimpan penunjuk langsung ke relasi-relasi yang menempel padanya, sehingga melangkah dari satu node ke node berikutnya tidak memerlukan pencarian indeks maupun pemindaian tabel. Biaya satu lompatan bersifat tetap, dan biaya kueri bertumbuh mengikuti jumlah lompatan yang ditempuh, bukan mengikuti ukuran seluruh graf. Kondisi ini berbeda dari penggabungan tabel pada basis data relasional, yang lebih dahulu mencocokkan baris melalui indeks sebelum hubungan antarbaris tersusun.

Diagram berikut memperlihatkan dua relasi pada data contoh, masing-masing dengan panah arah dan tipenya.

MENULISMEMINJAMAgam Prawira:PenulisTono:AnggotaRumah Pena:Buku
Dua relasi pada graf perpustakaan, masing-masing membawa satu arah dan satu tipe

Penelusuran bergerak dari relasi ke relasi, sehingga kueri yang menyentuh sedikit node bekerja dengan jumlah langkah yang sedikit pula. Kueri berikut melangkah dari anggota bernama Sari ke buku yang dipinjamnya melalui relasi :MEMINJAM, dengan langkah yang hanya menyentuh relasi yang menempel pada node tersebut.

cypher
MATCH (:Anggota {nama: "Sari"})-[r:MEMINJAM]->(b:Buku)
RETURN b.judul AS judul, r.tanggal AS tanggal ORDER BY judul
text Keluaran
judul, tanggal
"Catatan Pengelana", 2026-09-01
"Peta Angin", 2026-09-20

Arah dalam pola Cypher#

Arah relasi dibaca dalam pola Cypher melalui panah. Pola (a)-[:MEMINJAM]->(b) menuntun pembacaan dari node a menuju node b, sedangkan pola (a)<-[:MEMINJAM]-(b) membaca relasi yang sama dari sisi berlawanan. Panah pada pola harus mengikuti arah tersimpan apabila kueri menuntut arah tertentu, dan arah tersimpan ditetapkan saat relasi dibuat. Pada data contoh, relasi :MEMINJAM tersimpan dari anggota menuju buku.

Kueri berikut mencari relasi :MEMINJAM yang keluar dari buku Anak Muara, yaitu arah yang tidak pernah tersimpan pada data contoh.

cypher
MATCH (:Buku {judul: "Anak Muara"})-[:MEMINJAM]->(x)
RETURN count(x) AS jumlah
text Keluaran
jumlah
0

Membaca dari sisi berlawanan menggunakan panah kiri. Kueri berikut menempatkan buku pada sisi kiri pola sehingga relasi :MEMINJAM yang masuk kepadanya ditemukan, dan peminjam Anak Muara terlihat. Kedua kueri menyentuh relasi yang sama, tetapi kecocokan pola hanya terjadi apabila panah mengikuti arah tersimpan.

cypher
MATCH (:Buku {judul: "Anak Muara"})<-[:MEMINJAM]-(a:Anggota)
RETURN a.nama AS anggota ORDER BY anggota
text Keluaran
anggota
"Rina"

Menelusuri tanpa peduli arah#

Cypher mencocokkan relasi tanpa memedulikan arah apabila panah dihilangkan dari pola. Bentuk -[r:MEMINJAM]- diperiksa pada kedua arah oleh mesin kueri, sehingga pola tersebut menemukan relasi yang masuk maupun yang keluar dari node yang disentuhnya. Bentuk ini berguna apabila arah tersimpan belum diketahui atau apabila kueri memang bermakna dua arah. Pola tanpa panah tidak menghapus arah dari data, dan arah relasi yang ditemukan tetap dapat dibaca.

Kueri berikut menelusuri kedua arah dari buku Rumah Pena dengan tipe :MENULIS atau :MEMINJAM. Dua baris kembali, yaitu penulis dan peminjam buku tersebut, tanpa mengetahui arah tersimpan masing-masing relasi. Hasil yang sama dapat ditulis dengan dua pola berarah terpisah, tetapi bentuk tanpa panah lebih ringkas.

cypher
MATCH (n:Anggota|Penulis)-[r:MENULIS|MEMINJAM]-(b:Buku {judul: "Rumah Pena"})
RETURN n.nama AS dari, type(r) AS tipe ORDER BY tipe, dari
text Keluaran
dari, tipe
"Tono", "MEMINJAM"
"Agam Prawira", "MENULIS"

Tipe relasi sebagai kontrak#

Tipe relasi berperan sebagai kontrak makna antara data dan kueri. Nama tipe menyatakan peran hubungannya, dan setiap kueri yang menuliskan :MENULIS maupun :MEMINJAM bergantung pada ejaan tersebut. Berbeda dengan node yang boleh membawa beberapa label sekaligus, satu relasi tepat memiliki satu tipe, sehingga pemilihan tipe merupakan keputusan pemodelan yang menetap.

Fungsi type() membaca tipe relasi yang tertangkap dalam pola. Kueri berikut mengumpulkan relasi yang masuk ke buku Anak Muara, lalu memilahnya menurut tipe. Kolom label menegaskan kontrak tersebut, yaitu relasi :MENULIS datang dari node :Penulis, sedangkan relasi :MEMINJAM datang dari node :Anggota.

cypher
MATCH (n:Anggota|Penulis)-[r]->(b:Buku {judul: "Anak Muara"})
RETURN type(r) AS tipe, n.nama AS dari, labels(n) AS label
ORDER BY tipe, dari
text Keluaran
tipe, dari, label
"MEMINJAM", "Rina", ["Anggota"]
"MENULIS", "Hana Fadhila", ["Penulis"]
"MENULIS", "Nurul Widyastuti", ["Penulis"]

Pola juga dapat menerima lebih dari satu tipe sekaligus melalui alternasi dengan tanda pipa. Bentuk [:MENULIS|MEMINJAM] mencocokkan relasi bertipe salah satunya, dan bentuk inilah yang digunakan kueri penutup skrip penyiapan. Alternasi memperjelas niat kueri, yaitu kedua tipe dimaknai setara pada penelusuran tersebut. Kueri berikut menghitung kedua tipe pada data contoh lalu menampilkan jumlahnya per tipe.

cypher
MATCH (:Anggota|Penulis)-[r:MENULIS|MEMINJAM]->(:Buku)
RETURN type(r) AS tipe, count(r) AS jumlah ORDER BY tipe
text Keluaran
tipe, jumlah
"MEMINJAM", 5
"MENULIS", 6

Properti pada relasi secara ringkas#

Relasi dapat membawa properti sebagaimana node membawanya. Data contoh menggunakan satu properti relasi, yaitu tanggal pada :MEMINJAM yang mencatat kapan peminjaman terjadi. Penempatan semacam ini mengikuti prinsip bahwa fakta milik hubungan ditempel pada relasinya dan bukan disalin ke salah satu ujungnya, karena dua peminjaman berbeda pada pasangan node yang sama dapat membawa tanggal yang berbeda. Properti relasi ditulis dengan gaya nama yang sama dengan properti node, yaitu camelCase.

Predikat pada klausa WHERE menyaring relasi menurut propertinya, sebagaimana node disaring menurut propertinya pada kueri-kueri sebelumnya. Kueri berikut mencari seluruh peminjaman mulai tanggal 20 September 2026, dan kolom tanggal menampilkan nilai properti yang tersimpan pada relasinya.

cypher
MATCH (a:Anggota)-[r:MEMINJAM]->(b:Buku)
WHERE r.tanggal >= date("2026-09-20")
RETURN a.nama AS anggota, b.judul AS buku, r.tanggal AS tanggal
ORDER BY tanggal
text Keluaran
anggota, buku, tanggal
"Sari", "Peta Angin", 2026-09-20
"Wawan", "Jejak Basirah", 2026-09-25

Contoh di atas sekadar menyentuh mekanismenya, sedangkan pembahasan lengkap properti pada node dan relasi beserta penempatan fakta ada pada topik Properti. Arah menyatakan posisi, tipe menyatakan makna, dan properti menyatakan detail kejadian pada relasi yang sama.

Kesalahan umum#

Empat kesalahan berikut sering muncul saat topik ini dipraktikkan, beserta penyebab dan perbaikannya.

  1. Arah pola ditulis terbalik. Relasi :MEMINJAM tersimpan dari anggota menuju buku, sehingga pola (b:Buku)-[:MEMINJAM]->(x) menghasilkan nol baris tanpa pesan error. Perbaikannya adalah memeriksa arah tersimpan atau menuliskan pola tanpa panah agar kedua arah diperiksa.
  2. Ejaan tipe tidak konsisten. Nama tipe bersifat sensitif huruf, sehingga relasi yang dibuat dengan [:Meminjam] menjadi tipe baru dan kueri bertipe :MEMINJAM kosong tanpa peringatan. Perbaikannya adalah menuliskan tipe dengan huruf kapital sejak awal dan memeriksa daftar tipe melalui prosedur db.relationshipTypes().
  3. Satu relasi diberi lebih dari satu tipe. Node boleh membawa banyak label, tetapi satu relasi tepat memiliki satu tipe, sehingga makna tambahan tidak dapat ditulis sebagai tipe kedua pada relasi yang sama. Perbaikannya adalah memilih tipe yang paling mewakili lalu menaruh detail tambahan sebagai properti atau node tersendiri.
  4. Pola relasi ditulis tanpa tipe. Pola tanpa tipe memaksa mesin kueri memeriksa seluruh relasi yang menempel pada node, dan biayanya tumbuh mengikuti jumlah relasinya. Perbaikannya adalah mencantumkan tipe atau alternasi tipe agar pemeriksaan tetap murah.

Ringkasan#

  • Setiap relasi tersimpan dengan satu arah dan tepat satu tipe, dan tipe ditulis dengan huruf kapital mengikuti konvensi Neo4j.
  • Relasi adalah koneksi kelas satu yang tersimpan fisik bersama node ujungnya, sehingga setiap lompatan penelusuran berbiaya tetap.
  • Panah pada pola membaca arah tersimpan, sedangkan pola tanpa panah mencocokkan kedua arah sekaligus.
  • Tipe relasi berperan sebagai kontrak makna, dapat digabung melalui alternasi tanda pipa, dan relasi dapat membawa properti seperti tanggal peminjaman.

Referensi#