Neden Büyük Verilerin İşlevsel Olması Gerekir?


9

Stajım için son zamanlarda Big Data ile ilgili yeni bir proje üzerinde çalışmaya başladım. Yöneticilerim fonksiyonel programlamayı öğrenmeye başlamalarını önerdiler (Scala'yı şiddetle tavsiye ettiler). F # kullanarak hileli bir deneyim yaşadım, ancak bazı durumlarda pahalı olduğu için bu programlama paradigmasını kullanmanın önemini göremedim.

Dean bu konu hakkında ilginç bir konuşma yaptı ve neden "Büyük Veri" ile ilgili düşüncelerini burada paylaştı: http://www.youtube.com/watch?v=DFAdLCqDbLQ Ama Büyük Veri demek çok uygun değildi sadece Hadoop.

BigData çok belirsiz bir kavram olduğu için. Bir süre unutuyorum. Verilerle uğraşırken farklı yönleri karşılaştırmak, fonksiyonel yolun pahalı olup olmadığını görmek için basit bir örnek bulmaya çalıştım. İşlevsel programlama küçük veriler için pahalı ve bellek tüketiyorsa, neden Büyük Veri için buna ihtiyacımız var?

Süslü araçlardan çok, üç yaklaşım kullanarak belirli ve popüler bir sorun için bir çözüm oluşturmaya çalıştım: Zorunlu yol ve fonksiyonel yol (özyineleme, koleksiyonları kullanma). Üç yaklaşımı karşılaştırmak için zaman ve karmaşıklığı karşılaştırdım.

Scala'yı üç paradigma kullanarak bir algoritma yazmak için en iyi araç olduğu için bu işlevleri yazmak için kullandım

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))
}

Fonksiyonel yolu:

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))(_ + _)
}

Özyinelemeli yol:

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

Zorunlu yol:

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
}

Fonksiyonel programlamanın ağır olduğunu fark ettim! daha uzun zaman alır ve bellekte daha fazla yer kaplar. Kafam karıştı, bir makale okuduğumda veya bir konuşma izlediğimde, veri biliminde fonksiyonel programlamayı kullanmamız gerektiğini söylüyorlar. Doğru, özellikle veri dünyasında daha kolay ve daha üretken. ancak daha fazla zaman ve daha fazla bellek alanı gerektirir.

Öyleyse neden Büyük Veri'de Fonksiyonel programlama kullanmamız gerekiyor? Büyük Veri için işlevsel programlamayı (Scala) kullanmak için en iyi uygulamalar nelerdir?


5
Fonksiyonel programlama, kodunuzu paralel hale getirmeyi kolaylaştırır, bu nedenle tek bir işlemin bir iş parçacığında çalışması daha fazla zaman alsa bile, paralellik nedeniyle genel performans daha iyi olabilir.
Giorgio

@Giorgio: Paralelliğe en iyi performansı elde etmek için Aktör Modelleme olarak farklı paradigmalar vardır. Düşünmüyor musun?
user3047512

2
Sanırım basitçe hadoop'tan harita / indirgeme yaklaşımı fonksiyonel programlamadan bir fikir.
Doc Brown

1
@ user3047512: Örneğin, Erlang aktör modelini kullanır ve çoğunlukla işlevseldir.
Giorgio

2
"Büyük veri" fad ve FP arasındaki bağlantı o kadar da kolay değildir. "Büyük veri" de, harita indirgeme yaklaşımı modaya uygun bir yaklaşımdır ve bu da işlevsel programlama ahlakından esinlenmiştir. Bu benzerliğin bittiği yer, bu iki dünya arasında başka bir bağlantı göremiyorum.
SK-logic

Yanıtlar:


13

İşte nasıl görüyorum:

  • Oldukça belirsiz bir kavram oldukları için bir süre "büyük veri" kelimelerini görmezden gelelim

  • Hadoop'tan bahsettin. Hadoop 2 şey yapar: birden fazla makineye dağıtılan, yedekli, Hadoop API'sinden tek bir üniter sürücü gibi erişilebilen bir çeşit "sanal" sürücüye sahip olmanızı sağlar. Hadoop Dağıtılmış Dosya Sisteminde olduğu gibi HDFS olarak adlandırılır . Hadoop'un yaptığı bir diğer şey de, Harita Azaltma işlerini yürütmenize izin vermektir (bu, Harita Azaltma için bir çerçevedir). Biz kontrol ederse mapreduce Wikipedia sayfasını bunu görmek:

MapReduce, bir kümede paralel, dağıtılmış algoritmaya sahip büyük veri kümelerini işlemek için kullanılan bir programlama modelidir.

...

Bir MapReduce programı, filtreleme ve sıralama (öğrencileri adlarına göre sıralara ayırma, her ad için bir kuyruk) ve bir özet işlemini (sayıyı sayma gibi) gerçekleştiren bir Map () prosedüründen oluşur her bir sıradaki öğrencilerin adı, ad sıklıkları verir)

...

'MapReduce' çok sayıda bilgisayar kullanarak büyük veri kümelerinde paralelleştirilebilir sorunları işlemek için bir çerçevedir

Ayrıca bu sayfada, Hadoop

Hadoop, Apache'nin MapReduce'un ücretsiz ve açık kaynak uygulaması.

Şimdi, Hadoop fonksiyonel bir dil olmayan Java ile yazılmıştır. Ayrıca, Hadoop'un sayfasına bakarsak , Java'da nasıl MapReduce işi oluşturulacağına ve bir Hadoop kümesinde nasıl dağıtılacağına dair bir örnek buluruz .

İşte Hadoop için bir Fibonnaci MapReduce işi Java örneği.

Umarım bu sorunuzu cevaplar, yani BigData ve özellikle bir Fibonacci oluşturan MapReduce işinin işlevsel olması gerekmez ", yani isterseniz OO dillerinde uygulayabilirsiniz (örneğin).

Tabii ki bu BigData'nın "sadece" OO olması gerektiği anlamına gelmez. MapReduce benzeri bir işi uygulamak için işlevsel bir dili çok iyi kullanabilirsiniz. Eğer isterseniz, örneğin, aracılığıyla, Hadoop Scala kullanabilirsiniz haşlama .

Sanırım diğer noktalar da değinmeye değer.

Scala'da özyineleme yaparken, kodunuz buna izin veriyorsa, Scala kuyruk çağrı optimizasyonu yapacaktır . Bununla birlikte, JVM kuyruk çağrısı optimizasyonunu desteklemediğinden (henüz) , Scala bunu derleme zamanında, burada açıklandığı gibi yinelemeli çağrılarınızı döngülere eşdeğer kodla değiştirerek başarır . Bunun temel olarak anlamı, Scala kullanarak özyinelemeli ve özyinelemesiz kod karşılaştırmaları yapmanın anlamsız olmasıdır, çünkü her ikisi de çalışma zamanında aynı şeyi yapar.


2
OP tarafından önerilen kıstasları zayıflatan kuyruk çağrı optimizasyonunu desteklemeyen JVM hakkında mükemmel bir noktaya değindiniz. Bu çok bilgilendirici bir cevap, teşekkürler.
maple_shaft

1
Cevabınız için teşekkür ederim, Evet! kuyruk çağrı optimizasyonu gizli scala özelliklerinden biridir. stackoverflow.com/questions/1025181/hidden-features-of-scala/… . "Büyük Veri" nin sorunlarından biri, her şirketin farklı bir şekilde yeni bir teknoloji geliştirmeye çalışmasıdır. Ama esas olarak iki tane var: Hadoop teknolojisi ve diğerleri. Söylediğiniz gibi, sübjektiftir ve kendisiyle ilgili problemlerle ilgilidir, uzmanlığımıza göre doğru programlama paradigmasını da seçmeliyiz. Örneğin: Gerçek Zamanlı Öngörülü modeller Hadoop Platformlarında çok iyi çalışmaz.
user3047512

9

Tek bir makinede çalıştırabildiğiniz sürece, "Büyük Veri" değildir. Örnek probleminiz bu konuda herhangi bir şey göstermek için tamamen uygun değildir.

Büyük Veri, sorun boyutlarının o kadar büyük olduğu anlamına gelir ki işlemeyi dağıtmak bir optimizasyon değil, temel bir gereksinimdir. İşlevsel programlama, değiştirilemez veri yapıları ve vatansızlık nedeniyle doğru ve verimli dağıtılmış kod yazmayı çok daha kolaylaştırır.


"Büyük Veri, sorun boyutlarının o kadar büyük olduğu anlamına gelir ki işlemeyi dağıtmak bir optimizasyon değil, temel bir gereksinimdir." - Bir makineyi kullanarak TÜMÜNDE ne tür bir sorunun çözülemediğini anlamıyorum ve en az N> 1 olduğunda N gerektirir ...
Shivan Dragon

6
@ShivanDragon: Tek bir sistemde tamamlanması imkansız olan performans gereksinimlerini içeren bir tür problem. Veya veri boyutunun o kadar büyük olduğu yerlerde, tek bir sistem bunların tümünü bile depolayamaz.
Michael Borgwardt

Üzgünüm, şimdi ne demek istediğini anlıyorum. Bahsettiğiniz şeyin, daha spesifik olarak, BigData çatısı altında yaşayan MapReduce olduğunu söylemek doğru mu?
Shivan Dragon

Katıldığınız için teşekkür ederim, katılıyorum. Belki de bakış açımı göstermek için iyi bir örnek bulamadım. "Büyük Veri", geliştiricilerin 3V tanımını göz önünde bulundurarak günlük sorunlarımızı çözmek için verileri kullanmasının bir yoludur. Bir süreliğine 3V'yi unutacağım ve Data ile ilgilenen çok basit yönü konuşacağım. Verileri işlevsel bir şekilde analiz etmenin pahalı olduğunu görürsek, neden "Büyük Veri" nin işlevsel olması gerektiğini söylüyoruz? Demek istediğim bu.
user3047512

4
@ShivanDragon, örneğin, LHC saniyede birkaç gigabayt veri üretiyor . Tek bir makinenin böyle bir verimi bile işleyebileceğinden emin değilim.
SK-logic

4

Skala bilmiyorum ve bu nedenle fonksiyonel yaklaşımınız hakkında yorum yapamam, ancak kodunuz aşırıya kaçmış gibi görünüyor.

Diğer yandan özyinelemeli fonksiyonunuz verimsizdir. İşlev kendini iki kez çağırdığı için, yüksek verimsiz olan 2 ^ n düzenindedir. Üç yaklaşımı karşılaştırmak istiyorsanız, üç optimal uygulamayı karşılaştırmanız gerekir.

Fibonacci işlevi, işlevi yalnızca bir kez çağırarak yinelemeli olarak uygulanabilir. Daha genel bir tanım alalım:

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

Standart özel durum:

f0 = 0
f1 = 1

Genel özyinelemeli işlev:

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);
}

Teşekkürler! İyi bir noktaya değindin, ama bunu yinelemeli bir şekilde yapmanın etkili bir yolu yok. Bu çok yaygın bir prob (Fibonacci süiti). ve bu aynı problemi üç yolla ele almanın bir noktası. Herhangi bir programlama dili kullanarak bu prob çözmek için daha iyi bir yol önerebilir misiniz, ben scala kullanarak yeniden yazabilir ve aynı testleri yapmak?
user3047512

@ user3047512 Kuyruk özyinelemeyi destekleyen bir dil için, bunu bir akümülatörle yazabilirsiniz. Örnekler
toasted_flakes 7:13

Scala ayrıca gizli özellik olarak kuyruk özyinelemeyi de destekler oldfashionedsoftware.com/2008/09/27/…
user3047512 7:13

1
özyinelemeli çözüm saf fonksiyonu (çıkış fonksiyonu args ve sadece bağlıdır olduğu için @ user3047512 başka bir şey ), memoization iyi bir çözümdür. Basitçe söylemek gerekirse, her değer döndürdüğünde, bağımsız değişkenleri saklayıp bir anahtar / değer karmasıyla sonuçlanır ve işlev her çalıştırıldığında önce oraya bakın. Bu, saf işlevlerin avantajlarından biridir - bu işleve gelecekteki bir çağrı, önceden var olan karma değerini bulur ve sıfır hesaplamalar yapar, çünkü sonucun değişmeyeceğini biliyoruz.
Izkata

@ user3047512 Bu durumda yinelemeli versiyon da saf bir fonksiyona benziyor, ancak bu her zaman doğru değil - fonksiyonel bir dilde, dil tarafından daha iyi uygulandığına inanıyorum ...
Izkata

0

İşlevsel programlama küçük veriler için pahalı ve bellek tüketiyorsa, neden Büyük Veri için buna ihtiyacımız var?

Özellikle bunun son derece yararlı olduğu birkaç uygulamayı görebiliyorum. ex. İstatistikler, yani farklı parametrelerle anında bir Gauss fonksiyonunun hesaplanması veya veri analizi için bir dizi parametre. Sayısal analiz vb. İçin de enterpolasyon vardır.

Büyük Veri için işlevsel programlamayı (Scala) kullanmak için en iyi uygulamalar nelerdir?

Verimliliğe cevap vermek için uzayda veya zamanda verimliliğinizi artırmaya yardımcı olan teknikler de vardır, özellikle özyineleme, kuyruk özyineleme , devam geçiş tarzı , yüksek dereceli işlevler , vb. Bazı dillerin artıları ve eksileri vardır (örneğin tembel ve istekli.) Fibonnacci dizisi gibi basit bir şey, zaman zaman bazı iş arkadaşlarımın isteksiz olduğunu ve fonksiyonel programlama ile rahat olmayabileceğini ve dolayısıyla daha fazla geliştirme zamanı aldığını bulduğum için zorunlu yöntemi kullanabilirim ... hızlı, temiz ve "bu sübjektif bulsam da" kodunu bulduğumdan [sorumlu olduğum uygulamalar] yapabildiğim zaman fonksiyonel programlama kullanın.

Wikipedia, yayınlanan fibonnacci dizisinin "hızlı" bir versiyonuna sahiptir. 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)
}

Akışları / hof kullanma

val fibStream:Stream[Int] = 0 #:: 1 #:: (fibStream zip fibStream.tail).map{ t => t._1 + t._2 }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.