Spark #11 : Örtük dönüştürmeler


Bugun Scala implicit conversions'dan bahsediyoruz. Mesela ki, bir sekilde, iki integer toplamak istedigimde soyle bisey yapmak istiyorum:

scala> 1.plus(1)
<console>:24: error: value plus is not a member of Int
       1.plus(1)
      ^

Tabi boyle bisey yok. O zaman bir case class tanimliyorum:

scala> case class IntExtensions(value: Int){
         |     def plus(operand: Int) = value + operand
         | }
defined class IntExtensions

ve daha sonra:

scala> IntExtensions(1).plus(1)
res8: Int = 2

Bu sekilde calistirabilirim. Ama bu cok cirkin ve cok uzun. Her seferinde IntExtensions class'ini kullanmak istemiyorum. O zaman scala'nin implicit conversions guzelligini sahneye davet ediyorum:

scala> import scala.language.implicitConversions
import scala.language.implicitConversions

ve daha sonra implicit ve fonskyion tanimliyorum ki her bir integer'e, IntExtensions muamelesi yapabileyim:

scala> implicit def intToIntExtensions(value: Int) = {
        | IntExtensions(value)
        | }
intToIntExtensions: (value: Int)IntExtensions

scala> 1.plus(1)
res10: Int = 2

Bu sefer oldu. Guzelligi getirdi bizlere. 

Peki bunun spark ile ne alaksi var? Mesela sadece double tipinde kayitlar barindiran RDD'ler uzerinde calistirilabilecek metotlari diger tipte kayit tutan RDD'lerden ayirdedebilmek icin Spark, scala'nin bu dil ozelligini kullaniyor. 

Ornek olarak DoubleRDDFunctions class'ina goz atabiliriz. Double RDD dedigimiz basitce aslinda RDD[Double] tipine denk geliyor. RDD[Double] uzeirnde bir mean veya variance hesaplanabilirken, RDD[String] uzerinde bunlar hesaplanamaz. Bu ikisini ayirabilmek icin bir implicit conversion tanimlanmis, ve RDD[Double] olan tipler, implicit (gizli kapakli, ortulu bir sekilde) DoubleRDDFunctions tipine donusturuluyor. Ve bu sayede bu ekstra metotlar ulasilabilir hale geliyor. Bence harika estetik bir hareket spark'tan. 

Tekrar bir ornekle durumu incelersek:

scala> val kk = sc.parallelize(Seq(1.0, 2.0, 3.0))
kk: org.apache.spark.rdd.RDD[Double] = ParallelCollectionRDD[3] at parallelize at <console>:30

scala> kk.mean()
res11: Double = 2.0

Bu calisiyorken,

scala> val kk = sc.parallelize(Seq("a","b","c"))
kk: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[5] at parallelize at <console>:30

scala> kk.mean()
<console>:32: error: value mean is not a member of org.apache.spark.rdd.RDD[String]
            kk.mean()
                 ^

Bu patliyor. RDD[Double] uzerinde calistirdigimiz mean metodu, orjinal RDD class'inda yok. Boyle olunca ilk round compile-time'da fail ediyor. Daha sonra scala, implicit aramaya basliyor. Eger bu fail olmus tip uzerinde calisabilecek bir implicit fonksiyon bulabilirse onu calistiriyor ve donusum (yani RDD class'indan DoubleRDDFunctions class'ina olan donusum) otomatik olarak gerceklesiyor.

Ayni sekilde sadece key-value RDD'leri (pair RDD) uzerinde calistirilabilecek metodlar da yine PairRDDFunctions class'inda toplanmistir. Ve RDD --> PairRDDFunctions donusumu implicit olarak otomatik yapilir ve eger sizin bir pair RDD'niz var ise, bu metotlara ulasabilirsiniz. 

RDD uzerinde tanimli diger implicit donusumlere dokumantasyondan goz atabilirsiniz.


until then.





Yorumlar

Bu blogdaki popüler yayınlar

Python'da Multithreading ve Multiprocessing

Threat Modeling 1

Encoding / Decoding