Tuesday, January 27, 2015

Mengaplikasikan MapReduce untuk Mencari Mutual Friends ala Facebook

 FacebookMutualFriends
Facebook Mutual Friends
Facebook telah dikenal sebagai salah satu perusahaan web service yang sukses mengambil hati lebih dari satu miliar pengguna Internet di dunia. Guna tetap dapat memberikan layanan yang optimal kepada tiap usernya, Facebook telah menerapkan sejumlah teknologi Big Data seperti Apache Hadoop ( HDFS + MapReduce ) dan Apache HBase ( yang dikenal sebagai database Big Data ) untuk memproses aliran data dari para usernya tersebut. Dikatakan bahwa Facebook telah dibanjiri oleh sekitar 1,1 miliar pengguna aktif per-bulannya pada Maret 2013. Dalam artikel ini kita akan membahas bagaimana mengaplikasikan MapReduce untuk mencari Mutual Friends dari network pertemanan dalam Facebook.

Bagi mereka yang sudah mengenal MapReduce, pasti sudah akrab dengan program Wordcount, sebuah contoh program aplikasi MapReduce, yang boleh dianggap sebagai "Hello World!"-nya MapReduce. Aplikasi Wordcount, sesuai dengan namanya, berfungsi untuk menghitung kemunculan tiap kata dalam satu atau sekumpulan text file. Memahami aplikasi Wordcount adalah langkah pertama untuk mengerti cara kerja MapReduce.

Seperti telah dinyatakan diatas, kali ini kita akan membahas sebuah contoh use case MapReduce dalam dunia nyata, yaitu: Mencari jumlah Mutual Friends dari network pertemanan dalam Facebook dengan menggunakan MapReduce. Bagi para pengguna Facebook, pastinya sudah sangat familiar dengan istilah Mutual Friends ini. Lalu, bagaimana Facebook dapat menghitung dan meng-update jumlah Mutual Friends dari tiap usernya yang jumlahnya sudah melebihi satu miliar dan masih terus bertambah itu?


Facebook memiliki daftar pertemanan ( list of friends ), dan perlu dicatat bahwa friends atau pertemanan dalam Facebook bersifat dua arah : jika aku adalah temanmu maka kamu adalah temanku juga. Facebook juga memiliki server penyimpanan data yang sangat besar dan melayani ratusan juta permintaan akses setiap harinya. Berkaitan dengan hal ini, Facebook telah memutuskan untuk melakukan komputasi pendahuluan / pre-computation ( jika memungkinkan ) untuk mempersiapkan jawaban / responses terhadap permintaan akses yang jumlahnya ratusan juta tersebut. Hal ini diharapkan dapat memberikan respon yang lebih cepat terhadap suatu permintaan daripada melakukan komputasi setiap kali permintaan akses itu datang. Salah satu permintaan penghitungan yang sangat umum adalah Mutual Friends. Sebagai contoh, saat saya melihat profile Facebook milik Henny, saya dapat mengetahui berapa jumlah Mutual Friends antara saya dan Henny : "Kamu dan Henny memiliki 54 teman yang sama". Kemudian saya juga akan dapat mengetahui siapa saja yang termasuk dalam 54 orang tersebut. Jumlah teman yang sama atau Mutual Friends ini tentu saja tidak setiap saat berubah, jadi akan sangat mubazir jika Facebook harus selalu menghitung kembali setiap kali saya melihat profile-nya Henny.

Dalam kasus ini, kita akan menggunakan MapReduce untuk menghitung jumlah teman yang sama atau Mutual Friends dari setiap pengguna Facebook sekali sehari dan menyimpan hasilnya dalam bentuk Key Value Store ( Apache HBase ). Dengan demikian, setiap kali ada seorang pengguna yang melihat profile pengguna yang lain, maka jumlah teman yang sama atau Mutual Friends dari kedua orang ini dapat langsung diketahui dari database Key Value Store tanpa menghitungnya lagi.

Bagaimana algoritmanya? Kita dapat menyimpan daftar pertemanan dari seluruh user Facebook dalam bentuk pasangan Key->Value : Orang->[Daftar Teman]. Sebagai contoh, daftar pertemanan tersebut akan terlihat seperti berikut :

Annya -> [Brahm, Chieya, Dipa]
Brahm -> [Annya, Chieya, Dipa, Elsa]
Chieya -> [Annya, Brahm, Dipa, Elsa]
Dipa -> [Annya, Brahm, Chieya, Elsa]
Elsa -> [Brahm, Chieya, Dipa]

Setiap baris, yang merupakan pasangan key->value, akan menjadi argument dari sebuah Mapper dalam MapReduce. Mapper tersebut akan menghasilkan satu pasang key->value dari setiap teman dalam "Daftar Teman". Yang menjadi key adalah seorang teman dari "Daftar Teman" dan "Orang". Sedangkan yang menjadi value adalah "Daftar Teman". Kemudian, key akan diurut berdasarkan urutan alfabet (abjad).

Setelah proses Mapper selesai, maka daftar pertemanan diatas akan menjadi seperti berikut ( key diurut berdasar abjad sehingga semua pasangan pertemanan dari key yang sama akan diproses lanjut oleh Reducer yang sama pula dalam MapReduce) :

For map(Annya -> [Brahm, Chieya, Dipa]), hasilnya :
(Annya Brahm) -> [Brahm, Chieya, Dipa]
(Annya Chieya) -> [Brahm, Chieya, Dipa]
(Annya Dipa) -> [Brahm, Chieya, Dipa]

For map(Brahm -> [Annya, Chieya, Dipa, Elsa]), hasilnya : (pada bagian key dapat dilihat Annya ditulis lebih dahulu daripada Brahm)
(Annya Brahm) -> [Annya, Chieya, Dipa, Elsa]
(Brahm Chieya) -> [Annya, Chieya, Dipa, Elsa]
(Brahm Dipa) -> [Annya, Chieya, Dipa, Elsa]
(Brahm Elsa) -> [Annya, Chieya, Dipa, Elsa]

For map(Chieya -> [Annya, Brahm, Dipa, Elsa]), hasilnya:
(Annya Chieya) -> [Annya, Brahm, Dipa, Elsa]
(Brahm Chieya) -> [Annya, Brahm, Dipa, Elsa]
(Chieya Dipa) -> [Annya, Brahm, Dipa, Elsa]
(Chieya Elsa) -> [Annya, Brahm, Dipa, Elsa]

For map(Dipa -> [Annya, Brahm, Chieya, Elsa]), hasilnya:
(Annya Dipa) -> [Annya, Brahm, Chieya, Elsa]
(Brahm Dipa) -> [Annya, Brahm, Chieya, Elsa]
(Chieya Dipa) -> [Annya, Brahm, Chieya, Elsa]
(Dipa Elsa) -> [Annya, Brahm, Chieya, Elsa]

For map(Elsa -> [Brahm, Chieya, Dipa]), hasilnya:
(Brahm Elsa) -> [Brahm, Chieya, Dipa]
(Chieya Elsa) -> [Brahm, Chieya, Dipa]
(Dipa Elsa) -> [Brahm, Chieya, Dipa]

Sebelum pasangan key->value ini diproses lanjut oleh tiap Reducer-nya, kita akan mengelompokkannya berdasarkan key-nya masing-masing seperti berikut:

(Annya Brahm) -> [Annya, Chieya, Dipa, Elsa] [Brahm, Chieya, Dipa]
(Annya Chieya) -> [Annya, Brahm, Dipa, Elsa] [Brahm, Chieya, Dipa]
(Annya Dipa) -> [Annya, Brahm, Chieya, Elsa] [Brahm, Chieya, Dipa]
(Brahm Chieya) -> [Annya, Brahm, Dipa, Elsa] [Annya, Chieya, Dipa, Elsa]
(Brahm Dipa) -> [Annya, Brahm, Chieya, Elsa] [Annya, Chieya, Dipa, Elsa]
(Brahm Elsa) -> [Annya, Chieya, Dipa, Elsa] [Brahm, Chieya, Dipa]
(Chieya Dipa) -> [Annya, Brahm, Chieya, Elsa] [Annya, Brahm, Dipa, Elsa]
(Chieya Elsa) -> [Annya, Brahm, Dipa, Elsa] [Brahm, Chieya, Dipa]
(Dipa Elsa) -> [Annya, Brahm, Chieya, Elsa] [Brahm, Chieya, Dipa]

Tiap baris, yang merupakan pasangan key->[list of value] akan menjadi argument dari sebuah Reducer. Kemudian reduce function akan mengambil perpotongan / interseksi dari value yang terdapat dalam [list of value]. Output dari reduce function adalah key dan value ( yang tak lain adalah hasil dari interseksi tersebut) : key -> [hasil interseksi]. Sebagai contoh, reduce((Annya Brahm) -> [Annya, Chieya, Dipa, Elsa] [Brahm, Chieya, Dipa]) menghasilkan (Annya Brahm) -> [Chieya Dipa] yang berarti Annya dan Brahm memiliki 2 teman yang sama (Mutual Friends) yaitu Chieya dan Dipa.

Hasil dari dari seluruh proses Reducer adalah sebagai berikut:

(Annya Brahm) -> [Chieya Dipa]
(Annya Chieya) -> [Brahm Dipa]
(Annya Dipa) -> [Brahm Chieya]
(Brahm Chieya) -> [Annya Dipa Elsa]
(Brahm Dipa) -> [Annya Chieya Elsa]
(Brahm Elsa) -> [Chieya Dipa]
(Chieya Dipa) -> [Annya Brahm Elsa]
(Chieya Elsa) -> [Brahm Dipa]
(Dipa Elsa) -> [Brahm Chieya]


Nah, sekarang ketika Dipa melihat profile Brahm, kita dapat dengan cepat menunjuk pada key (Brahm Dipa) dan melihat bahwa mereka memiliki 3 teman yang sama ( Mutual Friends ) yaitu [Annya Chieya Elsa].

No comments: