Mengapa Data Besar Perlu Berfungsi?

9

Saya mulai mengerjakan proyek baru belakangan ini yang berhubungan dengan Big Data untuk magang saya. Manajer saya merekomendasikan untuk mulai belajar pemrograman fungsional (Mereka sangat merekomendasikan Scala). Saya memiliki pengalaman yang rendah hati menggunakan F #, tetapi saya tidak bisa melihat pentingnya menggunakan paradigma pemrograman ini karena mahal dalam beberapa kasus.

Dean memberikan ceramah menarik tentang topik ini, dan berbagi pemikirannya tentang mengapa "Big Data" di sini: http://www.youtube.com/watch?v=DFAdLCqDbLQ Tapi itu tidak terlalu nyaman karena Big Data tidak berarti hanya Hadoop.

Seperti konsep BigData yang sangat kabur. Aku melupakannya sebentar. Saya mencoba membuat satu contoh sederhana untuk membandingkan antara berbagai aspek ketika kita berurusan dengan data, untuk melihat apakah cara fungsional mahal atau tidak. Jika pemrograman fungsional mahal dan memakan banyak data kecil, mengapa kita membutuhkannya untuk Big Data?

Jauh dari alat mewah, saya mencoba membangun solusi untuk satu masalah khusus dan populer menggunakan tiga pendekatan: cara imperatif dan cara fungsional (rekursi, menggunakan koleksi). Saya membandingkan waktu dan kompleksitas, untuk membandingkan antara tiga pendekatan.

Saya menggunakan Scala untuk menulis fungsi-fungsi ini karena ini adalah alat terbaik untuk menulis algoritma menggunakan tiga paradigma

def main(args: Array[String]) {
    val start = System.currentTimeMillis()
    // Fibonacci_P
    val s = Fibonacci_P(400000000)
    val end = System.currentTimeMillis()
    println("Functional way: \n the Fibonacci sequence whose values do not exceed four million : %d \n Time : %d ".format(s, end - start))
    val start2 = System.currentTimeMillis()

    // Fibonacci_I
    val s2 = Fibonacci_I(40000000 0)
    val end2 = System.currentTimeMillis();
    println("Imperative way: \n the Fibonacci sequence whose values do not exceed four million : %d \n Time : %d ".format(s2, end2 - start2))
}

Cara fungsional:

def Fibonacci_P(max: BigInt): BigInt = {
    //http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream
    //lazy val Fibonaccis: Stream[Long] = 0 #:: 1 #:: Fibonaccis.zip(Fibonaccis.tail).map { case (a, b) => a + b }
    lazy val fibs: Stream[BigInt] = BigInt(0)#::BigInt(1)#::fibs.zip(fibs.tail).map {
        n = > n._1 + n._2
    }
    // println(fibs.takeWhile(p => p < max).toList)
    fibs.takeWhile(p = > p < max).foldLeft(BigInt(0))(_ + _)
}

Cara rekursif:

def Fibonacci_R(n: Int): BigInt = n match {
    case 1 | 2 = > 1
    case _ = > Fibonacci_R(n - 1) + Fibonacci_R(n - 2)
}

Cara imperatif:

def Fibonacci_I(max: BigInt): BigInt = {
    var first_element: BigInt = 0
    var second_element: BigInt = 1
    var sum: BigInt = 0

    while (second_element < max) {
        sum += second_element

        second_element = first_element + second_element
        first_element = second_element - first_element
    }

    //Return 
    sum
}

Saya perhatikan bahwa pemrograman fungsional sangat berat! dibutuhkan waktu lebih lama dan lebih banyak ruang dalam memori. Saya bingung, setiap kali saya membaca artikel atau menonton ceramah, mereka mengatakan bahwa kita harus menggunakan pemrograman fungsional dalam ilmu data. Benar, ini lebih mudah dan lebih produktif, khususnya di dunia data. tetapi membutuhkan lebih banyak waktu dan lebih banyak ruang memori.

Jadi, mengapa kita perlu menggunakan pemrograman Fungsional dalam Big Data? Apa praktik terbaik untuk menggunakan pemrograman fungsional (Scala) untuk Big Data?

pengguna3047512
sumber
5
Pemrograman fungsional membuatnya lebih mudah untuk memparalelkan kode Anda, sehingga meskipun satu operasi tunggal mungkin membutuhkan lebih banyak waktu untuk berjalan dalam satu utas, kinerja keseluruhan dapat lebih baik karena paralelisme.
Giorgio
@Iorgio: Ada berbagai paradigma sebagai Aktor Modeling untuk mendapatkan kinerja terbaik untuk paralelisme. Jangan pikir begitu?
user3047512
2
Saya kira itu hanya karena pendekatan peta / pengurangan dari hadoop adalah ide dari pemrograman fungsional.
Doc Brown
1
@ user3047512: Misalnya, Erlang menggunakan model aktor dan sebagian besar fungsional.
Giorgio
2
Koneksi antara mode "big data" dan FP tidak semudah itu. Dalam "Big data", pendekatan yang disebut peta-pereduksi adalah modis, yang, pada gilirannya, agak terinspirasi oleh etos pemrograman fungsional. Di sinilah kesamaan berakhir, saya tidak bisa melihat hubungan lebih lanjut antara kedua dunia ini.
SK-logic

Jawaban:

13

Begini cara saya melihatnya:

  • Mari kita abaikan kata-kata "data besar" untuk sementara waktu, karena itu adalah gagasan yang cukup kabur

  • Anda menyebutkan Hadoop. Hadoop melakukan 2 hal: memungkinkan Anda untuk memiliki semacam "virtual" drive yang didistribusikan pada banyak mesin, dengan redundansi, yang dapat diakses melalui API Hadoop seolah-olah itu adalah drive tunggal, kesatuan,. Ini disebut HDFS seperti dalam Sistem File Terdistribusi Hadoop . Hal lain yang dilakukan Hadoop adalah memungkinkan Anda untuk melakukan pekerjaan Pengurangan Peta (ini adalah kerangka kerja untuk Pengurangan Peta). Jika kami memeriksa halaman Wikipedia MapReduce , kami melihat bahwa:

MapReduce adalah model pemrograman untuk memproses set data besar dengan algoritma paralel dan terdistribusi pada sebuah cluster.

...

Program MapReduce terdiri dari prosedur Map () yang melakukan penyaringan dan penyortiran (seperti menyortir siswa berdasarkan nama depan ke dalam antrian, satu antrian untuk setiap nama) dan prosedur Reduce () yang melakukan operasi ringkasan (seperti menghitung angka) siswa di setiap antrian, menghasilkan frekuensi nama)

...

'MapReduce' adalah kerangka kerja untuk memproses masalah yang dapat diparalelkan di set data besar menggunakan sejumlah besar komputer

Juga di halaman ini, Hadoop digambarkan sebagai

Hadoop, implementasi MapReduce yang gratis dan open source dari Apache.

Sekarang, Hadoop ditulis dalam Java, yang bukan bahasa fungsional. Juga, jika kita melihat pada halaman Hadoop, kami juga menemukan contoh bagaimana membuat pekerjaan MapReduce di Jawa dan menyebarkannya dalam cluster Hadoop .

Berikut adalah contoh Java dari pekerjaan Fibonnaci MapReduce untuk Hadoop.

Saya harap ini menjawab pertanyaan Anda, yaitu BigData, dan khususnya pekerjaan MapReduce yang menciptakan Fibonacci tidak "perlu" berfungsi, alias Anda dapat mengimplementasikannya dalam bahasa OO jika Anda ingin (misalnya).

Tentu saja itu tidak berarti BigData "harus" hanya menjadi OO saja. Anda bisa menggunakan bahasa fungsional untuk mengimplementasikan pekerjaan seperti MapReduce. Anda dapat, misalnya, menggunakan Scala dengan Hadoop jika Anda mau, melalui Scalding .

Poin-poin lain yang menurut saya layak untuk disebutkan.

Saat melakukan rekursi di Scala, jika kode Anda memungkinkan, Scala akan melakukan optimasi panggilan-ekor . Namun, karena JVM belum (belum) mendukung optimisasi panggilan-ekor , Scala mencapai ini dengan mengganti, pada waktu kompilasi, panggilan rekursif Anda dengan kode yang setara dengan loop, seperti dijelaskan di sini . Apa ini pada dasarnya berarti bahwa melakukan tolok ukur kode rekursif vs non-rekursif menggunakan Scala tidak ada gunanya, karena mereka berdua akhirnya melakukan hal yang sama pada saat run time.

Shivan Dragon
sumber
2
Anda membuat poin yang sangat baik tentang JVM tidak mendukung optimasi panggilan ekor yang merusak tolok ukur yang diajukan oleh OP. Ini jawaban yang sangat informatif, terima kasih.
maple_shaft
1
Terima kasih atas jawaban Anda, Ya! tail-call-optimization adalah salah satu fitur scala tersembunyi. stackoverflow.com/questions/1025181/hidden-features-of-scala/… . Salah satu masalah "Big Data" adalah bahwa setiap perusahaan berusaha membangun teknologi baru dengan cara yang berbeda. Tapi ada dua: teknologi Hadoop dan lainnya. Seperti yang Anda katakan, itu subjektif dan terkait dengan masalah itu sendiri, kita harus memilih paradigma pemrograman yang tepat berdasarkan keahlian kita juga. Sebagai contoh: Model Prediktif Real-time tidak berfungsi dengan baik pada Platform Hadoop.
user3047512
9

Selama Anda bisa menjalankannya di satu mesin, itu bukan "Data Besar". Contoh masalah Anda sama sekali tidak pantas untuk menunjukkan apa pun tentangnya.

Big Data berarti bahwa ukuran masalah sangat besar sehingga mendistribusikan pemrosesan bukanlah optimasi tetapi persyaratan mendasar. Dan pemrograman fungsional membuatnya lebih mudah untuk menulis kode terdistribusi yang benar dan efisien karena struktur data yang tidak berubah dan statelessness.

Michael Borgwardt
sumber
"Big Data berarti bahwa ukuran masalahnya sangat besar sehingga mendistribusikan pemrosesan bukanlah optimasi tetapi persyaratan mendasar." - Saya tidak mengerti masalah apa yang TIDAK SEMUA bisa diselesaikan dengan menggunakan satu mesin, dan membutuhkan setidaknya N di mana N> 1 ...
Shivan Dragon
6
@ShivanDragon: Jenis masalah yang mencakup persyaratan kinerja yang sama sekali tidak mungkin dipenuhi pada satu sistem. Atau di mana ukuran data sangat besar sehingga tidak ada satu sistem pun yang dapat menyimpan semuanya.
Michael Borgwardt
Maaf, saya mengerti maksud Anda sekarang. Apakah benar mengatakan bahwa yang Anda maksud adalah, lebih khusus lagi, MapReduce yang hidup di bawah payung BigData?
Shivan Dragon
Terima kasih atas masukan Anda, saya setuju. Mungkin saya tidak dapat menemukan contoh sederhana yang bagus untuk menunjukkan sudut pandang saya. "Big Data" masih merupakan cara para pengembang menggunakan data untuk memecahkan masalah sehari-hari kita dengan mempertimbangkan definisi 3Vs. Saya akan melupakan 3V untuk sementara waktu dan berbicara tentang aspek yang sangat sederhana, berurusan dengan Data. Jika kita melihat bahwa menganalisis data dengan cara fungsional itu mahal, mengapa kita mengatakan bahwa "Data Besar" harus fungsional? Ini poin saya.
user3047512
4
@ ShivanDragon, misalnya, LHC menghasilkan beberapa gigabyte data per detik . Tidak yakin satu mesin pun dapat menangani throughput seperti itu.
SK-logic
4

Saya tidak tahu scala dan karena itu saya tidak bisa mengomentari pendekatan fungsional Anda, tetapi kode Anda terlihat seperti berlebihan.

Fungsi rekursif Anda di sisi lain tidak efisien. Karena fungsi memanggil dirinya sendiri dua kali, itu adalah urutan 2 ^ n, yang sangat tidak efisien. Jika Anda ingin membandingkan tiga pendekatan, Anda perlu membandingkan tiga implementasi optimal.

Fungsi Fibonacci dapat diimplementasikan secara rekursif dengan memanggil fungsi hanya sekali. Mari kita ambil definisi yang lebih umum:

F(0) = f0
F(1) = f1
F(n) = F(n-1) + F(n-2)

Kasus khusus standar adalah:

f0 = 0
f1 = 1

Fungsi rekursif umum adalah:

function fibonacci($f0, $f1, $n){
    if($n < 0 || !isInt($n)) return false;
    if($n = 0) return $f0;
    if($n = 1) return $f1;
    return fibonacci($f1, $f0 + $f1, $n - 1);
}
Lorenz Meyer
sumber
Terima kasih! Anda mengangkat poin yang baik, tetapi Tidak ada cara yang efisien untuk melakukannya dengan cara yang berulang. Ini adalah masalah yang sangat umum (Fibonacci suite). dan ini adalah poin dari penanganan masalah yang sama menggunakan tiga cara. Bisakah Anda menyarankan cara yang lebih baik untuk menyelesaikan masalah ini menggunakan bahasa pemrograman apa pun, saya dapat menulis ulang menggunakan scala dan melakukan tes yang sama?
user3047512
@ user3047512 Untuk bahasa yang mendukung rekursi ekor, Anda dapat menulisnya dengan akumulator. Contoh
toasted_flakes
Scala juga mendukung rekursi ekor sebagai fitur tersembunyi oldfashionedsoftware.com/2008/09/27/…
user3047512
1
@ user3047512 Karena solusi rekursif adalah fungsi murni (output hanya bergantung pada argumen fungsi dan tidak ada yang lain ), memoisasi adalah solusi yang baik. Sederhananya, setiap kali itu akan mengembalikan nilai, menyimpan argumen dan menghasilkan hash kunci / nilai, dan setiap kali fungsi dijalankan, lihat dulu di sana. Ini adalah salah satu keunggulan fungsi murni - panggilan ke fungsi ini di masa mendatang akan menemukan nilai hash yang sudah ada sebelumnya dan melakukan perhitungan nol , karena kami tahu hasilnya tidak akan berubah.
Izkata
@ user3047512 Versi iteratif juga terlihat seperti fungsi murni dalam kasus ini, tapi itu tidak selalu benar - dalam bahasa fungsional, saya percaya itu lebih baik ditegakkan oleh bahasa ...
Izkata
0

Jika pemrograman fungsional mahal dan memakan banyak data kecil, mengapa kita membutuhkannya untuk Big Data?

Secara khusus saya sudah dapat melihat beberapa aplikasi di mana ini sangat berguna. ex. Statistik, yaitu menghitung fungsi Gaussian dengan cepat dengan berbagai parameter atau satu set parameter untuk analisis data. Ada juga interpolasi untuk analisis numerik, dll.

Apa praktik terbaik untuk menggunakan pemrograman fungsional (Scala) untuk Big Data?

Untuk menjawab efisiensi ada juga teknik untuk membantu meningkatkan efisiensi Anda dalam ruang atau waktu, khususnya rekursi, rekursi ekor , gaya kelanjutan kelanjutan , fungsi tingkat tinggi , dll. Beberapa bahasa memiliki kelebihan dan kekurangannya (misalnya malas vs bersemangat.) Untuk sesuatu yang sederhana seperti urutan Fibonnacci Saya mungkin hanya menggunakan cara imperatif seperti yang saya temukan pada waktu beberapa rekan kerja saya enggan dan mungkin tidak nyaman dengan pemrograman fungsional dan karenanya membutuhkan waktu pengembangan lebih banyak ... (Saya masih lebih suka untuk menggunakan pemrograman fungsional ketika saya dapat [aplikasi yang saya bertanggung jawab]) karena saya merasa cepat, bersih dan "mudah dibaca" (walaupun saya menemukan ini subjektif) kode.

Wikipedia memiliki versi "cepat" dari urutan fibonnacci yang diposting. https://en.wikipedia.org/wiki/Functional_programming#Scala

def fibTailRec(n: Int): Int = {
  @tailrec def f(a: Int, b: Int, c: Int): Int = if (a == 0) 0 else if(a < 2) c else f(a-1, c, b + c)
  f(n, 0, 1)
}

Menggunakan stream / hof

val fibStream:Stream[Int] = 0 #:: 1 #:: (fibStream zip fibStream.tail).map{ t => t._1 + t._2 }
LxsScarredCrest
sumber