Memakai Graph Database Dengan Neo4j


Selama beberapa dekade terakhir ini, database relasional berbasis tabel boleh dibilang merupakan jenis database yang paling sering dipakai dan paling dewasa. Database relasional tidak akan hilang dalam jangka waktu dekat ini, tapi mereka memiliki keterbatasan sendiri. Sebagai contoh, database relasional akan kewalahan melakukan query yang dibutuhkan untuk keperluan jejaring sosial seperti Facebook dan Twitter. Database relasional memang memiliki JOIN untuk menggabungkan tabel, tapi JOIN yang mereka miliki tidak memiliki arah dan label. Salah satu jenis database yang diciptakan untuk mengembalikan makna ‘relasional’ tersebut adalah graph database.

Graph yang dimaksud pada graph database adalah definisi graph pada graph theory yang merupakan bagian dari ilmu matematika diskrit. Paper pertama yang membahas graph theory ditulis oleh Leonhard Eulear pada tahun 1736 yang membahas tentang permasalahan Konigsberg Bridge.

Pada kesempatan ini, saya akan mencoba menggunakan sebuah graph database populer, Neo4j. Saya harus mulai dari mana? Pada database relasional, saya bisa mulai dengan merancang tabel dengan merancang skema dengan menggunakan ERD. Berbeda dari database relasional, sebuah graph database tidak memiliki skema seperti tabel dan kolom yang berbeda dengan isi (record). Segala sesuatunya adalah data! Oleh sebab itu, pada saat merancang untuk graph database, saya bisa langsung memakai contoh data. Sebagai latihan, saya akan membuat database yang menampung produk yang dibeli oleh pengguna seperti berikut ini:

Contoh rancangan untuk graph database

Contoh rancangan untuk graph database

Pada rancangan di atas, masing-masing lingkaran mewakili sebuah node. Setiap node terhubung ke node lain melalui garis yang memiliki arah yang disebut sebagai edge. Baik node maupun edge boleh memiliki properties. Berkebalikan dari database relasional, nilai properties pada node atau edge akan lebih baik bila sebisa mungkin di-‘normalisasi’ menjadi node sehingga bisa dipakai secara efisien di query.

Setelah menentukan rancangan database, sekarang saatnya untuk memasukkan data. Saya sudah menyiapkan beberapa data dalam bentuk CSV untuk dimasukkan sebagai isi dari database Neo4j. Saya akan mulai dengan membuat seluruh node yang mewakili produk. Untuk itu, setelah menjalankan Neo4j, saya membuka browser dan menampilkan http://localhost:7474. Ini adalah halaman web dimana saya bisa mengelola database Neo4j dan juga mengerjakan query (dalam bentuk Cypher). Sebagai contoh, saya memberikan perintah seperti pada gambar berikut ini:

Mengisi data dari file CSV

Mengisi data dari file CSV

Saya juga melakukan hal yang sama untuk menciptakan node yang mewakili pengguna, misalnya dengan memberikan perintah Cypher berikut ini:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:C:/user.csv" AS row
CREATE (:User {id: row.id});

Karena kedua node ini akan sering dicari berdasarkan id, maka saya bisa memberikan index. id bersifat unik sehingga saya bisa menggunakan perintah CREATE CONSTRAINTS yang akan menciptakan unique index yang lebih cepat dibandingkan index biasa. Sebagai contoh, saya memberikan perintah berikut ini:

CREATE CONSTRAINT ON (p:Produk) ASSERT p.id IS UNIQUE;
CREATE CONSTRAINT ON (u:User) ASSERT u.id IS UNIQUE

Sekarang adalah saatnya untuk membuat edge BELI dari User ke Produk. Saya melakukannya dengan memberikan perintah seperti berikut ini:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:C:/buys.csv" AS row
MATCH (user:User {id: row.user_id})
MATCH (produk:Produk {id: row.produk_id})
MERGE (user)-[:BELI]->(produk);

Setelah ini, saya bisa mulai belajar mencari data. Bila pada database relasional terdapat SQL, maka Neo4j menggunakan query khusus yang disebut sebagai Cypher. Bahasa query ini juga deklaratif seperti SQL dan dirancang agar mudah dipahami. Sebagai contoh, untuk menampilkan 25 node user pertama, saya dapat menggunakan Cyhper seperti:

MATCH (n:User) RETURN n LIMIT 25;
Hasil query dalam bentuk tabel

Hasil query dalam bentuk tabel

Tidak ada yang berbeda dari database relasional bila node dikembalikan dalam bentuk tabel. Agar lebih menarik, saya bisa menampilkan hasil query dalam bentuk grafis seperti yang terlihat pada gambar berikut ini:

Hasil query dalam bentuk graph

Hasil query dalam bentuk graph

Tidak seperti hasil query dari database relasional yang sulit dicerna secara langsung, hasil query pada graph database cukup menarik untuk diamati. Pengguna juga bisa menemukan pola data secara visual.

Contoh lain dari query Cypher adalah:

MATCH (u:User {id:"xxx"})-[:BELI]->(p:Produk)
RETURN p;

Klausa MATCH pada query di atas akan mencari node User yang memiliki id "xxx" dan memiliki asosiasi BELI terhadap node Produk. Setelah itu, klausa RETURN akan mengembalikan seluruh node Produk yang ada. Dengan kata lain, query ini akan mengembalikan seluruh produk yang dibeli oleh pengguna dengan id "xxx". Tentu saja query seperti ini juga bisa dilakukan secara mudah dengan menggunakan SQL di database relasional.

Untuk menunjukkan sesuatu yang tidak gampang dilakukan melalui SQL, saya akan memberikan query Cypher seperti berikut ini:

MATCH (u1:User)-[:BELI]->(p:Produk)<-[:BELI]-(u2:User) 
RETURN p;

Hasilnya akan terlihat seperti pada gambar berikut ini:

Hasil query dalam bentuk graph

Hasil query dalam bentuk graph

Dengan menggunakan arah panah seperti -[:BELI]-> dan <-[:BELI]-, query di atas akan mengembalikan seluruh node Produk yang minimal sudah dibeli oleh 2 pengguna. Karena saya tidak peduli dengan node User pada query di atas, saya bisa mengabaikannya dengan mengubah query menjadi seperti berikut ini:

MATCH ()-[:BELI]->(p:Produk)<-[:BELI]-()
RETURN p;

Selain mengembalikan node, saya juga bisa mengembalikan property sehingga memperoleh hasil dalam bentuk tabel. Sebagai contoh, saya bisa memberikan query seperti berikut ini:

MATCH (u1:User)-[:BELI]->(p:Produk)<-[:BELI]-(u2:User)
RETURN u1.id AS user1, p.url AS produk, u2.id AS user2;

Ingin sesuatu yang lebih sulit dilakukan melalui query SQL? Sebagai contoh, saya akan mencari produk lain yang dibeli oleh pengguna lain yang juga membeli produk yang sama dengan seorang pengguna dengan menggunakan query seperti berikut ini:

MATCH (u1:User)-[:BELI]->(p1:Produk)<-[:BELI]-(u2:User),
      (u2)-[:BELI]->(p2:Produk)
RETURN p1, p2;
Hasil query dalam bentuk graph

Hasil query dalam bentuk graph

Karena graph database memang dirancang untuk keperluan seperti Cypher di atas, ia bukan hanya menawarkan kemudahan, tapi juga kinerja yang lebih baik dibandingkan query serupa yang memakai database relasional. Walaupun penelusuran tetapi dilakukan satu per satu seperti pada JOIN di database relasional, setiap node bisa memiliki path yang berbeda. Begitu path untuk node sudah melenceng dari yang diharapkan, ia bisa segera diabaikan sehingga penelusuran bisa segera dilanjutkan.

Saya juga menggabungkan MATCH di Cypher di atas sehingga menjadi seperti berikut ini:

MATCH (u1:User)-[:BELI]->(p1:Produk)<-[:BELI]-(u2:User)-[:BELI]->(p2:Produk)
RETURN p1, p2;

Tergantung pada selera, versi yang terakhir ini mungkin lebih mudah dipahami dibandingkan dengan versi sebelumnya.

Sama seperti di SQL, untuk mebatasi query di Cypher saya juga dapat menggunakan klausa WHERE. Sebagai contoh, bila saya hanya tertarik pada produk dengan id 'xxx', maka saya bisa memberikan query seperti berikut ini:

MATCH (u1:User)-[:BELI]->(p1:Produk)<-[:BELI]-(u2:User)-[:BELI]->(p2:Produk)
WHERE p1.id = "xxx"
RETURN u1, p1, u2, p2;
Hasil query dalam bentuk graph

Hasil query dalam bentuk graph

Pada gambar di atas, id 5969 adalah nilai internal yang diberikan untuk produk 'xxx'. Terlihat bahwa user seperti user 329, 3953, 5149 dan sejenisnya membeli produk 'xxx' bersamaan dengan produk lain.

Pada query diatas, akan ada banyak produk ganda yang ditampilkan karena beberapa pengguna berbeda bisa saja melihat banyak produk yang sama. Sama seperti di SQL, untuk mengembalikan hanya produk yang unik, saya dapat menggunakan klausa DISTINCT seperti pada contoh berikut ini:

MATCH (u1:User)-[:BELI]->(p1:Produk)<-[:BELI]-(u2:User)-[:BELI]->(p2:Produk)
WHERE p1.id = "xxx" 
RETURN DISTINCT p1, u2, p2;

Perihal Solid Snake
I'm nothing...

2 Responses to Memakai Graph Database Dengan Neo4j

  1. jtxmisc mengatakan:

    termakasih infonya, sangat bermanfaat , Abla

  2. Joko Wahono mengatakan:

    bolehkah saya minta data csv nya sebagai contoh ?? saya sudah membuat tetapi tidak mau memproses di neo4j nya ? apkah formatnya yg salah juga saya tidak tahu..

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: