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?
sumber
Jawaban:
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:
...
...
Juga di halaman ini, Hadoop digambarkan sebagai
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.
sumber
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.
sumber
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:
Kasus khusus standar adalah:
Fungsi rekursif umum adalah:
sumber
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.
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
Menggunakan stream / hof
sumber