sparkle 0.7.2.1 → 0.7.3
raw patch · 22 files changed
+840/−201 lines, 22 filesdep +constraints
Dependencies added: constraints
Files
- CHANGELOG.md +33/−1
- README.md +12/−1
- build.gradle +4/−5
- build/libs/sparkle.jar binary
- sparkle.cabal +8/−2
- src/Control/Distributed/Spark.hs +4/−3
- src/Control/Distributed/Spark/Closure.hs +79/−1
- src/Control/Distributed/Spark/ML/Feature/CountVectorizer.hs +1/−1
- src/Control/Distributed/Spark/ML/Feature/RegexTokenizer.hs +1/−1
- src/Control/Distributed/Spark/ML/Feature/StopWordsRemover.hs +1/−1
- src/Control/Distributed/Spark/PairRDD.hs +43/−51
- src/Control/Distributed/Spark/RDD.hs +19/−1
- src/Control/Distributed/Spark/SQL/Column.hs +2/−1
- src/Control/Distributed/Spark/SQL/DataFrame.hs +0/−119
- src/Control/Distributed/Spark/SQL/Dataset.hs +364/−0
- src/Control/Distributed/Spark/SQL/Encoder.hs +148/−0
- src/Control/Distributed/Spark/SQL/SparkSession.hs +38/−0
- src/Language/Scala/Tuple.hs +42/−0
- src/main/java/Helper.java +4/−12
- src/main/java/io/tweag/sparkle/function/HaskellFlatMapFunction.java +1/−1
- src/main/java/io/tweag/sparkle/function/HaskellMapPartitionsFunction.java +18/−0
- src/main/java/io/tweag/sparkle/function/HaskellReduceFunction.java +18/−0
CHANGELOG.md view
@@ -8,8 +8,36 @@ ### Added +### Changed++## [0.7.3] - 2018-02-06++### Added++* More `RDD` method bindings: `randomSplit`, `mean`,+ `zipWithUniqueId`, `reduceByKey`, `subtractByKey`.++### Changed++* Use inline-java for PairRDD bindings under the hood.+* Updated sparkle to build with distributed-closure-0.4.0.++## [0.7.2] - 2017-12-25++### Added+ * More `RDD` method bindings: `sortBy`. +## [0.7.1] - 2017-12-13++### Fixed++* Use StaticPointers for `PairRDD` as a workaround for [GHC bug+ #14204][ghc-14204] occuring when mapping over a PairRDD (see [issue+ #119][issue-119])++## [0.7] - 2017-12-09+ ## [0.6] - 2017-07-16 ### Added@@ -65,7 +93,7 @@ * Support Template Haskell splices and `ANN` annotations that use sparkle code. -### Changed +### Changed ### Fixed @@ -115,3 +143,7 @@ ## [0.1.0] - 2016-04-25 * Initial release++[ghc-14204]: https://ghc.haskell.org/trac/ghc/ticket/14204+[hackage-choice]: https://hackage.haskell.org/package/choice+[issue-119]: https://github.com/tweag/sparkle/issues/119
README.md view
@@ -19,7 +19,7 @@ ``` $ stack build hello $ stack exec -- sparkle package sparkle-example-hello-$ stack exec -- spark-submit --master 'local[1]' sparkle-example-hello.jar+$ stack exec -- spark-submit --master 'local[1]' --packages com.amazonaws:aws-java-sdk:1.11.253,org.apache.hadoop:hadoop-aws:2.7.2,com.google.guava:guava:23.0 sparkle-example-hello.jar ``` ## How to use@@ -188,6 +188,17 @@ See [#104](https://github.com/tweag/sparkle/issues/104) for more details.++### java.lang.UnsatisfiedLinkError: /tmp/sparkle-app...: failed to map segment from shared object++Sparkle unzips the Haskell binary program in a temporary location on+the filesystem and then loads it from there. For loading to succeed, the+temporary location must not be mounted with the `noexec` option.+Alternatively, the temporary location can be changed with+```+spark-submit --driver-java-options="-Djava.io.tmpdir=..." \+ --conf "spark.executor.extraJavaOptions=-Djava.io.tmpdir=..."+``` ### java.io.IOException: No FileSystem for scheme: s3n
build.gradle view
@@ -5,13 +5,12 @@ } dependencies {- compile 'org.apache.spark:spark-core_2.10:1.6.0'- compile 'org.apache.spark:spark-mllib_2.10:1.6.0'+ compile 'org.apache.spark:spark-core_2.11:2.2.0'+ compile 'org.apache.spark:spark-mllib_2.11:2.2.0' } -compileJava {- sourceCompatibility = 1.7- targetCompatibility = 1.7+dependencies {+ compile files(buildscript.sourceFile.getParent() + "/build/libs/sparkle.jar") } jar {
build/libs/sparkle.jar view
binary file changed (13104 → 14334 bytes)
sparkle.cabal view
@@ -1,5 +1,5 @@ name: sparkle-version: 0.7.2.1+version: 0.7.3 synopsis: Distributed Apache Spark applications in Haskell description: See https://www.stackage.org/package/sparkle. homepage: http://github.com/tweag/sparkle#readme@@ -23,6 +23,8 @@ src/main/java/io/tweag/sparkle/function/HaskellFunction2.java src/main/java/io/tweag/sparkle/function/HaskellFunction3.java src/main/java/io/tweag/sparkle/function/HaskellFunction4.java+ src/main/java/io/tweag/sparkle/function/HaskellMapPartitionsFunction.java+ src/main/java/io/tweag/sparkle/function/HaskellReduceFunction.java src/main/java/io/tweag/sparkle/function/HaskellVoidFunction.java src/main/java/io/tweag/sparkle/kryo/InlineJavaRegistrator.java CHANGELOG.md@@ -57,18 +59,22 @@ Control.Distributed.Spark.PairRDD Control.Distributed.Spark.SQL.Column Control.Distributed.Spark.SQL.Context- Control.Distributed.Spark.SQL.DataFrame+ Control.Distributed.Spark.SQL.Dataset+ Control.Distributed.Spark.SQL.Encoder Control.Distributed.Spark.SQL.Row Control.Distributed.Spark.SQL.StructType Control.Distributed.Spark.SQL.StructField Control.Distributed.Spark.SQL.DataType Control.Distributed.Spark.SQL.Metadata+ Control.Distributed.Spark.SQL.SparkSession Control.Distributed.Spark.RDD+ Language.Scala.Tuple build-depends: base >=4.10.1.0 && <5, binary >=0.7, bytestring >=0.10, choice >= 0.1,+ constraints, distributed-closure >=0.3, inline-java >=0.7.0 && <0.8, jni >=0.5.0 && <0.6,
src/Control/Distributed/Spark.hs view
@@ -8,11 +8,12 @@ import Control.Distributed.Spark.ML.Feature.StopWordsRemover as S import Control.Distributed.Spark.ML.LDA as S import Control.Distributed.Spark.PairRDD as S-import Control.Distributed.Spark.SQL.Column as S+import Control.Distributed.Spark.SQL.Column as S hiding+ (mean) import Control.Distributed.Spark.SQL.Context as S-import Control.Distributed.Spark.SQL.DataFrame as S hiding- (distinct, filter, join, schema)+import Control.Distributed.Spark.SQL.Encoder as S import Control.Distributed.Spark.SQL.Row as S+import Control.Distributed.Spark.SQL.SparkSession as S import Control.Distributed.Spark.RDD as S import Foreign.JNI.Types (JNIEnv, JClass) import Foreign.Ptr (Ptr)
src/Control/Distributed/Spark/Closure.hs view
@@ -5,16 +5,21 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StaticPointers #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fplugin=Language.Java.Inline.Plugin #-} module Control.Distributed.Spark.Closure- ( ReifyFun(..)+ ( MapPartitionsFunction(..)+ , ReduceFunction(..)+ , ReifyFun(..) , ReflectFun(..) , JFun1 , JFun2@@ -36,6 +41,8 @@ import Foreign.Ptr (Ptr) import GHC.TypeLits (Nat) import Language.Java+import Language.Java.Inline+import Streaming (Stream, Of) -- | The main entry point for Java code to apply a Haskell 'Closure'. This -- function is foreign exported.@@ -166,4 +173,75 @@ wrap :: Closure (JObjectArray -> IO JObject) wrap = $(cstatic 'closFun2) `cap` ($(cstatic 'tripleDict) `cap` closureDict `cap` closureDict `cap` closureDict) `cap`+ f++newtype ReduceFunction a = ReduceFunction (Closure (a -> a -> a))++instance Interpretation a => Interpretation (ReduceFunction a) where+ type Interp (ReduceFunction a) =+ 'Iface "org.apache.spark.api.java.function.ReduceFunction" <> '[Interp a]++instance (Interpretation (ReduceFunction a), Typeable (a -> a -> a)) =>+ Reify (ReduceFunction a) where+ reify jobj0 = do+ let jobj = cast jobj0+ ReduceFunction . bs2clos <$> ([java| $jobj.clos |] >>= reify)+ where+ cast+ :: J (Interp (ReduceFunction a))+ -> J ('Class "io.tweag.sparkle.function.HaskellReduceFunction")+ cast = unsafeCast++instance ( Static (Reify a)+ , Static (Reflect a)+ , Typeable a+ ) =>+ Reflect (ReduceFunction a) where+ reflect (ReduceFunction f) = do+ jpayload <- reflect (clos2bs wrap)+ generic <$>+ [java| new io.tweag.sparkle.function.HaskellReduceFunction($jpayload) |]+ where+ wrap :: Closure (JObjectArray -> IO JObject)+ wrap = closure (static closFun2) `cap`+ (closure (static tripleDict)+ `cap` closureDict `cap` closureDict `cap` closureDict+ ) `cap` f++newtype MapPartitionsFunction a b =+ MapPartitionsFunction (Closure (Stream (Of a) IO () -> Stream (Of b) IO ()))+instance (Interpretation a, Interpretation b) =>+ Interpretation (MapPartitionsFunction a b) where+ type Interp (MapPartitionsFunction a b) =+ 'Iface "org.apache.spark.api.java.function.MapPartitionsFunction"+ <> [Interp a, Interp b]++instance ( Interpretation (MapPartitionsFunction a b)+ , Typeable (Stream (Of a) IO () -> Stream (Of b) IO ())+ ) =>+ Reify (MapPartitionsFunction a b) where+ reify jobj0 = do+ let jobj = cast jobj0+ MapPartitionsFunction . bs2clos <$> ([java| $jobj.clos |] >>= reify)+ where+ cast+ :: J (Interp (MapPartitionsFunction a b))+ -> J ('Class "io.tweag.sparkle.function.HaskellMapPartitionsFunction")+ cast = unsafeCast++instance ( Static (Reify (Stream (Of a) IO ()))+ , Static (Reflect (Stream (Of b) IO ()))+ , Interpretation (MapPartitionsFunction a b)+ , Typeable (Stream (Of a) IO ())+ , Typeable (Stream (Of b) IO ())+ ) =>+ Reflect (MapPartitionsFunction a b) where+ reflect (MapPartitionsFunction f) = do+ jpayload <- reflect (clos2bs wrap)+ generic <$>+ [java| new io.tweag.sparkle.function.HaskellMapPartitionsFunction($jpayload) |]+ where+ wrap :: Closure (JObjectArray -> IO JObject)+ wrap = $(cstatic 'closFun1) `cap`+ ($(cstatic 'pairDict) `cap` closureDict `cap` closureDict) `cap` f
src/Control/Distributed/Spark/ML/Feature/CountVectorizer.hs view
@@ -10,7 +10,7 @@ import Control.Distributed.Spark.RDD (RDD) import Control.Distributed.Spark.PairRDD-import Control.Distributed.Spark.SQL.DataFrame+import Control.Distributed.Spark.SQL.Dataset import Data.Int import Data.Text (Text) import Foreign.C.Types
src/Control/Distributed/Spark/ML/Feature/RegexTokenizer.hs view
@@ -8,7 +8,7 @@ module Control.Distributed.Spark.ML.Feature.RegexTokenizer where -import Control.Distributed.Spark.SQL.DataFrame+import Control.Distributed.Spark.SQL.Dataset import Data.Text (Text) import Language.Java
src/Control/Distributed/Spark/ML/Feature/StopWordsRemover.hs view
@@ -8,7 +8,7 @@ module Control.Distributed.Spark.ML.Feature.StopWordsRemover where -import Control.Distributed.Spark.SQL.DataFrame+import Control.Distributed.Spark.SQL.Dataset import Data.Text (Text) import Language.Java
src/Control/Distributed/Spark/PairRDD.hs view
@@ -1,18 +1,18 @@+-- | Bindings for+-- <https://spark.apache.org/docs/latest/api/java/org/apache/spark/api/java/JavaPairRDD.html org.apache.spark.api.java.JavaPairRDD>.+-- {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE StaticPointers #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE UndecidableInstances #-} +{-# OPTIONS_GHC -fplugin=Language.Java.Inline.Plugin #-}+ module Control.Distributed.Spark.PairRDD where import Control.Distributed.Closure-import Control.Distributed.Closure.TH import Control.Distributed.Spark.Closure (reflectFun) import Control.Distributed.Spark.Context import Control.Distributed.Spark.RDD@@ -20,49 +20,64 @@ import Data.Text (Text) import Data.Typeable (Typeable) import Language.Java+import Language.Java.Inline (java)+import Language.Scala.Tuple newtype PairRDD a b = PairRDD (J ('Class "org.apache.spark.api.java.JavaPairRDD")) deriving Coercible zipWithIndex :: RDD a -> IO (PairRDD a Int64)-zipWithIndex rdd = call rdd "zipWithIndex" []--toRDD :: PairRDD a b -> IO (RDD (Tuple2 a b))-toRDD prdd = do- scalaRDD <- call prdd "rdd" []- call (scalaRDD :: J ('Class "org.apache.spark.rdd.RDD")) "toJavaRDD" []+zipWithIndex rdd = [java| $rdd.zipWithIndex() |] fromRDD :: RDD (Tuple2 a b) -> IO (PairRDD a b) fromRDD rdd =- callStatic- "org.apache.spark.api.java.JavaPairRDD"- "fromJavaRDD"- [coerce rdd]+ [java| org.apache.spark.api.java.JavaPairRDD.fromJavaRDD($rdd) |] +toRDD :: PairRDD a b -> IO (RDD (Tuple2 a b))+toRDD prdd = [java| $prdd.rdd().toJavaRDD() |]+ join :: PairRDD a b -> PairRDD a c -> IO (PairRDD a (Tuple2 b c))-join prdd0 prdd1 = call prdd0 "join" [coerce prdd1]+join prdd0 prdd1 = [java| $prdd0.join($prdd1) |] keyBy :: (Static (Reify v), Static (Reflect k), Typeable v, Typeable k) => Closure (v -> k) -> RDD v -> IO (PairRDD k v) keyBy byKeyOp rdd = do- jbyKeyOp <- reflectFun (sing :: Sing 1) byKeyOp- call rdd "keyBy" [ coerce jbyKeyOp ]+ jbyKeyOp <- unsafeUngeneric <$> reflectFun (sing :: Sing 1) byKeyOp+ [java| $rdd.keyBy($jbyKeyOp) |] mapValues :: (Static (Reify a), Static (Reflect b), Typeable a, Typeable b) => Closure (a -> b) -> PairRDD k a -> IO (PairRDD k b) mapValues f prdd = do- jf <- reflectFun (sing :: Sing 1) f- call prdd "mapValues" [coerce jf]+ jf <- unsafeUngeneric <$> reflectFun (sing :: Sing 1) f+ [java| $prdd.mapValues($jf) |] +zipWithUniqueId :: RDD a -> IO (PairRDD a Int64)+zipWithUniqueId rdd = [java| $rdd.zipWithUniqueId() |]++reduceByKey+ :: (Static (Reify v), Static (Reflect v), Typeable v)+ => Closure (v -> v -> v)+ -> PairRDD k v+ -> IO (PairRDD k v)+reduceByKey clos rdd = do+ f <- unsafeUngeneric <$> reflectFun (sing :: Sing 2) clos+ [java| $rdd.reduceByKey($f) |]++subtractByKey+ :: PairRDD a b+ -> PairRDD a c+ -> IO (PairRDD a b)+subtractByKey prdd0 prdd1 = [java| $prdd0.subtractByKey($prdd1) |]+ wholeTextFiles :: SparkContext -> Text -> IO (PairRDD Text Text) wholeTextFiles sc uri = do juri <- reflect uri- call sc "wholeTextFiles" [coerce juri]+ [java| $sc.wholeTextFiles($juri) |] justValues :: PairRDD a b -> IO (RDD b)-justValues prdd = call prdd "values" []+justValues prdd = [java| $prdd.values() |] aggregateByKey :: (Static (Reify a), Static (Reify b), Static (Reflect b), Typeable a, Typeable b)@@ -72,36 +87,13 @@ -> PairRDD k a -> IO (PairRDD k b) aggregateByKey seqOp combOp zero prdd = do- jseqOp <- reflectFun (sing :: Sing 2) seqOp- jcombOp <- reflectFun (sing :: Sing 2) combOp+ jseqOp <- unsafeUngeneric <$> reflectFun (sing :: Sing 2) seqOp+ jcombOp <- unsafeUngeneric <$> reflectFun (sing :: Sing 2) combOp jzero <- upcast <$> reflect zero- call prdd "aggregateByKey"- [coerce jzero, coerce jseqOp, coerce jcombOp]+ [java| $prdd.aggregateByKey($jzero, $jseqOp, $jcombOp) |] zip :: RDD a -> RDD b -> IO (PairRDD a b)-zip rdda rddb = call rdda "zip" [coerce rddb]+zip rdda rddb = [java| $rdda.zip($rddb) |] sortByKey :: PairRDD a b -> IO (PairRDD a b)-sortByKey prdd = call prdd "sortByKey" []--data Tuple2 a b = Tuple2 a b- deriving (Show, Eq)--withStatic [d|-- instance Interpretation (Tuple2 a b) where- type Interp (Tuple2 a b) = 'Class "scala.Tuple2"-- instance (Reify a, Reify b) =>- Reify (Tuple2 a b) where- reify jobj =- Tuple2 <$> ((call jobj "_1" [] :: IO JObject) >>= reify . unsafeCast)- <*> ((call jobj "_2" [] :: IO JObject) >>= reify . unsafeCast)-- instance (Reflect a, Reflect b) =>- Reflect (Tuple2 a b) where- reflect (Tuple2 a b) = do- ja <- reflect a- jb <- reflect b- new [coerce $ upcast ja, coerce $ upcast jb]- |]+sortByKey prdd = [java| $prdd.sortByKey() |]
src/Control/Distributed/Spark/RDD.hs view
@@ -9,7 +9,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StaticPointers #-}@@ -31,6 +30,7 @@ , aggregate , treeAggregate , count+ , mean , collect , take , distinct@@ -38,6 +38,7 @@ , union , sortBy , sample+ , randomSplit , first , getNumPartitions , saveAsTextFile@@ -48,11 +49,14 @@ import Prelude hiding (filter, map, subtract, take) import Control.Distributed.Closure import Control.Distributed.Spark.Closure (reflectFun)+import Control.Monad import Data.Choice (Choice) import qualified Data.Choice as Choice import Data.Int import qualified Data.Text as Text import Data.Typeable (Typeable)+import Data.Vector.Storable as V (fromList)+import Foreign.JNI import Language.Java import Language.Java.Inline -- We don't need this instance. But import to bring it in scope transitively for users.@@ -170,6 +174,10 @@ count :: RDD a -> IO Int64 count rdd = [java| $rdd.count() |] >>= reify +mean :: RDD Double -> IO Double+mean rdd =+ [java| $rdd.mapToDouble(r -> (double)r).mean() |]+ subtract :: RDD a -> RDD a -> IO (RDD a) subtract rdd1 rdd2 = [java| $rdd1.subtract($rdd2) |] @@ -216,6 +224,16 @@ -> Double -- ^ fraction of elements to keep -> IO (RDD a) sample rdd replacement frac = [java| $rdd.sample($replacement, $frac) |]++randomSplit+ :: RDD a+ -> [Double] -- ^ Statistical weights of RDD fractions.+ -> IO [RDD a]+randomSplit rdd weights = do+ jweights <- reflect $ V.fromList weights+ arr :: JObjectArray <- [java| $rdd.randomSplit($jweights) |]+ n <- getArrayLength arr+ forM [0 .. n - 1] (getObjectArrayElement arr) first :: Reify a => RDD a -> IO a first rdd = do
src/Control/Distributed/Spark/SQL/Column.hs view
@@ -23,7 +23,8 @@ newtype Column = Column (J ('Class "org.apache.spark.sql.Column")) deriving (Coercible, Interpretation, Reflect, Reify) -newtype GroupedData = GroupedData (J ('Class "org.apache.spark.sql.GroupedData"))+newtype GroupedData =+ GroupedData (J ('Class "org.apache.spark.sql.RelationalGroupedDataset")) deriving (Coercible, Interpretation, Reflect, Reify) alias :: Column -> Text -> IO Column
− src/Control/Distributed/Spark/SQL/DataFrame.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}--module Control.Distributed.Spark.SQL.DataFrame where--import Control.Distributed.Spark.RDD-import Control.Distributed.Spark.SQL.Column-import Control.Distributed.Spark.SQL.Context-import Control.Distributed.Spark.SQL.Row-import Control.Distributed.Spark.SQL.StructType-import qualified Data.Coerce-import Data.Int-import Data.Text (Text)-import Language.Java-import Prelude hiding (filter)--newtype DataFrame = DataFrame (J ('Class "org.apache.spark.sql.DataFrame"))- deriving (Coercible, Interpretation, Reify, Reflect)--toDF :: SQLContext -> RDD Row -> Text -> Text -> IO DataFrame-toDF sqlc rdd s1 s2 = do- col1 <- reflect s1- col2 <- reflect s2- callStatic "Helper" "toDF" [coerce sqlc, coerce rdd, coerce col1, coerce col2]--javaRDD :: DataFrame -> IO (RDD Row)-javaRDD df = call df "javaRDD" []--createDataFrame :: SQLContext -> RDD Row -> StructType -> IO DataFrame-createDataFrame sqlc rdd st =- call sqlc "createDataFrame" [coerce rdd, coerce st]--debugDF :: DataFrame -> IO ()-debugDF df = call df "show" []--range :: Int64 -> Int64 -> Int64 -> Int32 -> SQLContext -> IO DataFrame-range start end step partitions sqlc =- call sqlc "range" [coerce start, coerce end, coerce step, coerce partitions]--join :: DataFrame -> DataFrame -> IO DataFrame-join d1 d2 = call d1 "join" [coerce d2]--joinOn :: DataFrame -> DataFrame -> Column -> IO DataFrame-joinOn d1 d2 colexpr = call d1 "join" [coerce d2, coerce colexpr]--newtype DataFrameReader = DataFrameReader (J ('Class "org.apache.spark.sql.DataFrameReader"))- deriving Coercible--newtype DataFrameWriter = DataFrameWriter (J ('Class "org.apache.spark.sql.DataFrameWriter"))- deriving Coercible--read :: SQLContext -> IO DataFrameReader-read sc = call sc "read" []--write :: DataFrame -> IO DataFrameWriter-write df = call df "write" []--readParquet :: [Text] -> DataFrameReader -> IO DataFrame-readParquet fps dfr = do- jfps <- reflect fps- call dfr "parquet" [coerce jfps]--writeParquet :: Text -> DataFrameWriter -> IO ()-writeParquet fp dfw = do- jfp <- reflect fp- call dfw "parquet" [coerce jfp]--schema :: DataFrame -> IO StructType-schema df = call df "schema" []--select :: DataFrame -> [Column] -> IO DataFrame-select d1 colexprs =- toArray (Data.Coerce.coerce colexprs- :: [J ('Class "org.apache.spark.sql.Column")])- >>= call d1 "select" . (:[]) . coerce--filter :: DataFrame -> Column -> IO DataFrame-filter d1 colexpr = call d1 "where" [coerce colexpr]--unionAll :: DataFrame -> DataFrame -> IO DataFrame-unionAll d1 d2 = call d1 "unionAll" [coerce d2]--distinct :: DataFrame -> IO DataFrame-distinct d = call d "distinct" []--withColumnRenamed :: Text -> Text -> DataFrame -> IO DataFrame-withColumnRenamed old newName df = do- jold <- reflect old- jnew <- reflect newName- call df "withColumnRenamed" [coerce jold, coerce jnew]--col :: DataFrame -> Text -> IO Column-col d1 t = do- colName <- reflect t- call d1 "col" [coerce colName]--columns :: DataFrame -> IO [Text]-columns df = call df "columns" [] >>= reify--printSchema :: DataFrame -> IO ()-printSchema df = call df "printSchema" []--groupBy :: DataFrame -> [Column] -> IO GroupedData-groupBy d1 colexprs =- toArray (Data.Coerce.coerce colexprs- :: [J ('Class "org.apache.spark.sql.Column")])- >>= call d1 "groupBy" . (:[]) . coerce--agg :: GroupedData -> [Column] -> IO DataFrame-agg _ [] = error "agg: not enough arguments."-agg df (Column jcol : cols) = do- jcols <- toArray (Data.Coerce.coerce cols- :: [J ('Class "org.apache.spark.sql.Column")])- call df "agg" [coerce jcol, coerce jcols]
+ src/Control/Distributed/Spark/SQL/Dataset.hs view
@@ -0,0 +1,364 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StaticPointers #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++{-# OPTIONS_GHC -fplugin=Language.Java.Inline.Plugin #-}++module Control.Distributed.Spark.SQL.Dataset where++import Control.Distributed.Closure+import Control.Distributed.Spark.Closure+import Control.Distributed.Spark.RDD (RDD)+import Control.Distributed.Spark.SQL.Column+import Control.Distributed.Spark.SQL.Encoder+import Control.Distributed.Spark.SQL.Row+import Control.Distributed.Spark.SQL.StructType+import Control.Distributed.Spark.SQL.SparkSession+import Data.Int+import Data.Text (Text)+import Data.Typeable+import Foreign.JNI+import Language.Java+import Language.Java.Inline (java)+import Prelude hiding (filter)+import Streaming (Stream, Of, effect)+import qualified Streaming.Prelude as S (filter, fold_, map, yield)+import System.IO.Unsafe (unsafeDupablePerformIO, unsafePerformIO)++newtype Dataset a = Dataset (J ('Class "org.apache.spark.sql.Dataset"))+ deriving Coercible++type DataFrame = Dataset Row++javaRDD :: Dataset a -> IO (RDD a)+javaRDD df = [java| $df.javaRDD() |]++createDataset :: SparkSession -> Encoder a -> RDD a -> IO (Dataset a)+createDataset ss enc rdd = [java| $ss.createDataset($rdd.rdd(), $enc) |]++getEncoder :: forall a. Dataset a -> IO (Encoder a)+getEncoder ds = do+ let klass = unsafeDupablePerformIO $ withLocalRef+ (findClass $+ referenceTypeName (SClass "org.apache.spark.sql.Dataset"))+ newGlobalRef+ fID = unsafePerformIO $+ getFieldID klass+ "org$apache$spark$sql$Dataset$$encoder"+ (signature (sing :: Sing (Interp (Encoder a))))+ (Encoder+ . (unsafeCast :: JObject -> J ('Iface "org.apache.spark.sql.Encoder"))+ )+ <$> getObjectField ds fID++as :: Encoder b -> Dataset a -> IO (Dataset b)+as enc ds = [java| $ds.as($enc) |]++createDataFrame :: SparkSession -> RDD Row -> StructType -> IO DataFrame+createDataFrame ss rdd st = [java| $ss.createDataFrame($rdd, $st) |]++sparkSession :: Dataset a -> IO SparkSession+sparkSession ds = [java| $ds.sparkSession() |]++cache :: Dataset a -> IO (Dataset a)+cache ds = [java| $ds.cache() |]++unpersist :: Dataset a -> IO (Dataset a)+unpersist ds = [java| $ds.unpersist(false) |]++withColumnRenamed :: Text -> Text -> Dataset a -> IO (Dataset Row)+withColumnRenamed old newt df = do+ jold <- reflect old+ jnew <- reflect newt+ [java| $df.withColumnRenamed($jold, $jnew) |]++toDF :: [Text] -> Dataset a -> IO (Dataset Row)+toDF cols df = do+ jcols <- reflect cols+ [java| $df.toDF($jcols) |]++selectDS :: Dataset a -> [Text] -> IO (Dataset Row)+selectDS _ [] = error "selectDS: not enough arguments."+selectDS df (c:cols) = do+ jcol <- reflect c+ jcols <- reflect cols+ [java| $df.select($jcol, $jcols) |]++limit :: Int32 -> Dataset a -> IO (Dataset a)+limit n df = [java| $df.limit($n) |]++show :: Dataset a -> IO ()+show df = [java| { $df.show(); } |]++range+ :: Int64+ -> Int64+ -> Int64+ -> Int32+ -> SparkSession+ -> IO (Dataset Int64)+range start end step partitions ss =+ [java| $ss.range($start, $end, $step, $partitions) |]++union :: Dataset a -> Dataset a -> IO (Dataset a)+union ds1 ds2 = [java| $ds1.union($ds2) |]++join :: Dataset a -> Dataset b -> IO (Dataset Row)+join d1 d2 = [java| $d1.join($d2) |]++joinOn :: Dataset a -> Dataset b -> Column -> IO DataFrame+joinOn d1 d2 colexpr = [java| $d1.join($d2, $colexpr) |]++crossJoin :: Dataset a -> Dataset b -> IO (Dataset Row)+crossJoin d1 d2 = [java| $d1.crossJoin($d2) |]++sample :: Bool -> Double -> Dataset a -> IO (Dataset Row)+sample withReplacement fraction d1 =+ [java| $d1.sample($withReplacement, $fraction) |]++dropDuplicates :: [Text] -> Dataset a -> IO (Dataset Row)+dropDuplicates cols ds = do+ jCols <- reflect cols+ [java| $ds.dropDuplicates($jCols) |]++orderBy :: [Column] -> Dataset a -> IO (Dataset Row)+orderBy cols ds = do+ jCols <- reflect cols+ [java| $ds.orderBy($jCols) |]++except :: Dataset a -> Dataset a -> IO (Dataset Row)+except ds1 ds2 = [java| $ds1.except($ds2) |]++intersect :: Dataset a -> Dataset a -> IO (Dataset Row)+intersect ds1 ds2 = [java| $ds1.intersect($ds2) |]++columns :: Dataset a -> IO [Text]+columns df = [java| $df.columns() |] >>= reify++printSchema :: Dataset a -> IO ()+printSchema df = [java| { $df.printSchema(); } |]++distinct :: Dataset a -> IO (Dataset a)+distinct d = [java| $d.distinct() |]++repartition :: Int32 -> Dataset a -> IO (Dataset a)+repartition nbPart d = [java| $d.repartition($nbPart) |]++coalesce :: Int32 -> Dataset a -> IO (Dataset a)+coalesce nbPart ds = [java| $ds.coalesce($nbPart) |]++collectAsList :: forall a. Reify a => Dataset a -> IO [a]+collectAsList d =+ [java| $d.collectAsList().toArray() |] >>= reify . jcast+ where+ jcast :: JObjectArray -> J ('Array (Interp a))+ jcast = unsafeCast++newtype DataFrameReader = DataFrameReader (J ('Class "org.apache.spark.sql.DataFrameReader"))+ deriving Coercible++newtype DataFrameWriter = DataFrameWriter (J ('Class "org.apache.spark.sql.DataFrameWriter"))+ deriving Coercible++read :: SparkSession -> IO DataFrameReader+read ss = [java| $ss.read() |]++write :: Dataset a -> IO DataFrameWriter+write df = call df "write" []++readParquet :: [Text] -> DataFrameReader -> IO DataFrame+readParquet fps dfr = do+ jfps <- reflect fps+ call dfr "parquet" [coerce jfps]++writeParquet :: Text -> DataFrameWriter -> IO ()+writeParquet fp dfw = do+ jfp <- reflect fp+ call dfw "parquet" [coerce jfp]++formatReader :: Text -> DataFrameReader -> IO DataFrameReader+formatReader source dfr = do+ jsource <- reflect source+ [java| $dfr.format($jsource) |]++formatWriter :: Text -> DataFrameWriter -> IO DataFrameWriter+formatWriter source dfw = do+ jsource <- reflect source+ [java| $dfw.format($jsource) |]++optionReader :: Text -> Text -> DataFrameReader -> IO DataFrameReader+optionReader key value dfr = do+ jkey <- reflect key+ jv <- reflect value+ [java| $dfr.option($jkey, $jv) |]++optionWriter+ :: Text -> Text -> DataFrameWriter -> IO DataFrameWriter+optionWriter key value dfw = do+ jkey <- reflect key+ jv <- reflect value+ [java| $dfw.option($jkey, $jv) |]++load :: Text -> DataFrameReader -> IO DataFrame+load path dfr = do+ jpath <- reflect path+ [java| $dfr.load($jpath) |]++save :: Text -> DataFrameWriter -> IO ()+save path dfw = do+ jpath <- reflect path+ [java| { $dfw.save($jpath); } |]++schema :: Dataset a -> IO StructType+schema df = [java| $df.schema() |]++select :: Dataset a -> [Column] -> IO DataFrame+select d1 colexprs = do+ jCols <- reflect colexprs+ [java| $d1.select($jCols) |]++whereDS :: Dataset a -> Column -> IO (Dataset a)+whereDS d1 colexpr = [java| $d1.where($colexpr) |]++count :: Dataset a -> IO Int64+count df = [java| $df.count() |]++col :: Dataset a -> Text -> IO Column+col d1 t = do+ colName <- reflect t+ [java| $d1.col($colName) |]++filter+ :: ( Reflect (MapPartitionsFunction a a)+ , Typeable a+ )+ => Closure (a -> Bool)+ -> Dataset a+ -> IO (Dataset a)+filter clos ds = do+ enc <- getEncoder ds+ mapPartitions clos' enc ds+ where clos' = closure (static S.filter) `cap` clos++filterByCol :: Column -> Dataset a -> IO (Dataset a)+filterByCol c ds = [java| $ds.filter($c) |]++map :: forall a b.+ ( Reflect (MapPartitionsFunction a b)+ , Typeable b+ , Typeable a+ )+ => Closure (a -> b)+ -> Encoder b+ -> Dataset a+ -> IO (Dataset b)+map clos enc ds = mapPartitions clos' enc ds+ where+ clos' :: Closure (Stream (Of a) IO () -> Stream (Of b) IO ())+ clos' = closure (static S.map) `cap` clos++aggregate+ :: ( Reflect (MapPartitionsFunction a b)+ , Reflect (ReduceFunction b)+ , Reify b+ , Static (Serializable b)+ , Typeable a+ )+ => Closure (b -> a -> b)+ -> Closure (b -> b -> b)+ -> b+ -> Dataset a+ -> IO b+aggregate seqOp combOp zero =+ aggregatePartitions seqOp' combOp+ where+ seqOp' = (closure $ static (\f z -> S.fold_ f z id))+ `cap` seqOp+ `cap` cpure closureDict zero++-- | Like 'aggregate', but exposing the underlying iterator+aggregatePartitions+ :: forall a b.+ ( Reflect (MapPartitionsFunction a b)+ , Reflect (ReduceFunction b)+ , Reify b+ , Typeable a+ , Typeable b+ )+ => Closure (Stream (Of a) IO () -> IO b)+ -> Closure (b -> b -> b)+ -> Dataset a -> IO b+aggregatePartitions seqOp combOp ds = do+ enc <- kryo+ reducePartitions seqOp enc ds+ >>= slowReduce combOp++mapPartitions+ :: Reflect (MapPartitionsFunction a b)+ => Closure (Stream (Of a) IO () -> Stream (Of b) IO ())+ -> Encoder b+ -> Dataset a+ -> IO (Dataset b)+mapPartitions clos enc ds = do+ f <- unsafeUngeneric <$> reflect (MapPartitionsFunction clos)+ [java| $ds.mapPartitions($f, $enc) |]++-- | Like 'mapPartitions', but for a function that produces only a single+-- element partition+reducePartitions+ :: ( Reflect (MapPartitionsFunction a b)+ , Typeable a+ , Typeable b+ )+ => Closure (Stream (Of a) IO () -> IO b)+ -> Encoder b+ -> Dataset a+ -> IO (Dataset b)+reducePartitions fun =+ mapPartitions+ (closure (static (\f it -> effect $ S.yield <$> f it)) `cap` fun)++reduce+ :: forall a. (Static (Reify a), Static (Reflect a), Typeable a)+ => Closure (a -> a -> a)+ -> Dataset a+ -> IO a+reduce clos ds = do+ f <- unsafeUngeneric <$> reflect (ReduceFunction clos)+ [java| $ds.reduce($f) |]+ >>= reify . jcast+ where+ jcast :: JObject -> J (Interp a)+ jcast = unsafeCast++slowReduce+ :: forall a. (Reflect (ReduceFunction a), Reify a)+ => Closure (a -> a -> a)+ -> Dataset a+ -> IO a+slowReduce clos ds = do+ f <- unsafeUngeneric <$> reflect (ReduceFunction clos)+ [java| $ds.reduce($f) |]+ >>= reify . jcast+ where+ jcast :: JObject -> J (Interp a)+ jcast = unsafeCast++groupBy :: forall a . Dataset a -> [Column] -> IO GroupedData+groupBy d1 colexprs = do+ cols <- reflect colexprs+ [java| $d1.groupBy($cols) |]++agg :: GroupedData -> [Column] -> IO (Dataset Row)+agg _ [] = error "agg: not enough arguments."+agg df (Column jcol : cols) = do+ jcols <- reflect cols+ [java| $df.agg($jcol, $jcols) |]
+ src/Control/Distributed/Spark/SQL/Encoder.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fplugin=Language.Java.Inline.Plugin #-}++module Control.Distributed.Spark.SQL.Encoder+ ( long+ , string+ , int+ , short+ , boolean+ , float+ , double+ , tuple2+ , javaSerialization+ , kryo+ , coerceEncoder+ , getRowEncoder+ , Encoder(..)+ , HasEncoder(..)+ ) where++import Control.Distributed.Spark.SQL.Row+import Control.Distributed.Spark.SQL.StructType++import qualified Data.Coerce+import Data.Constraint (Dict(Dict))+import Data.Int+import Data.Singletons (SingI)+import Data.Text (Text)++import Language.Java+import Language.Java.Inline (java)+import Language.Scala.Tuple+import Foreign.JNI+import System.IO.Unsafe (unsafePerformIO)++newtype Encoder a = Encoder (J ('Iface "org.apache.spark.sql.Encoder"))+ deriving (Coercible, Interpretation)++{-# NOINLINE long #-}+long :: Encoder Int64+long = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.LONG() |]+ newGlobalRefNonFinalized++{-# NOINLINE string #-}+string :: Encoder Text+string = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.STRING() |]+ newGlobalRefNonFinalized++{-# NOINLINE int #-}+int :: Encoder Int32+int = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.INT() |]+ newGlobalRefNonFinalized++{-# NOINLINE short #-}+short :: Encoder Int16+short = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.SHORT() |]+ newGlobalRefNonFinalized++{-# NOINLINE boolean #-}+boolean :: Encoder Bool+boolean = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.BOOLEAN() |]+ newGlobalRefNonFinalized++{-# NOINLINE float #-}+float :: Encoder Float+float = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.FLOAT() |]+ newGlobalRefNonFinalized++{-# NOINLINE double #-}+double :: Encoder Double+double = unsafePerformIO $+ withLocalRef [java| org.apache.spark.sql.Encoders.DOUBLE() |]+ newGlobalRefNonFinalized++tuple2 :: Encoder a -> Encoder b -> IO (Encoder (Tuple2 a b))+tuple2 ea eb = [java| org.apache.spark.sql.Encoders.tuple($ea, $eb) |]++javaSerialization :: forall a ty. (Interp a ~ ty, SingI ty, IsReferenceType ty)+ => IO (Encoder a)+javaSerialization = do+ cls <- findClass (referenceTypeName (sing :: Sing ty))+ [java| org.apache.spark.sql.Encoders.javaSerialization($cls) |]++kryo :: forall a ty. (Interp a ~ ty, SingI ty, IsReferenceType ty)+ => IO (Encoder a)+kryo = do+ cls <- findClass (referenceTypeName (sing :: Sing ty))+ [java| org.apache.spark.sql.Encoders.kryo($cls) |]++coerceEncoder :: forall a b . Interp a ~ Interp b => Encoder a -> Encoder b+coerceEncoder = Data.Coerce.coerce+ where+ _ = Dict @(Interp a ~ Interp b)++getRowEncoder :: StructType -> IO (Encoder Row)+getRowEncoder st =+ [java| org.apache.spark.sql.catalyst.encoders.RowEncoder.apply($st) |]++-- | Class of types which have encoders+class HasEncoder a where+ encoder :: IO (Encoder a)++instance HasEncoder Int64 where+ encoder = newLocalRef long++instance HasEncoder Text where+ encoder = newLocalRef string++instance HasEncoder Float where+ encoder = newLocalRef float++instance HasEncoder Double where+ encoder = newLocalRef double++instance HasEncoder Int32 where+ encoder = newLocalRef int++instance HasEncoder Int16 where+ encoder = newLocalRef short++instance HasEncoder Bool where+ encoder = newLocalRef boolean++instance (HasEncoder a, HasEncoder b) => HasEncoder (Tuple2 a b) where+ encoder = do+ a <- encoder+ b <- encoder+ tuple2 a b
+ src/Control/Distributed/Spark/SQL/SparkSession.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fplugin=Language.Java.Inline.Plugin #-}++module Control.Distributed.Spark.SQL.SparkSession where++import Control.Distributed.Spark.Context+import Language.Java+import Language.Java.Inline (java)++newtype SparkSession =+ SparkSession (J ('Class "org.apache.spark.sql.SparkSession"))+ deriving Coercible++newtype Builder =+ Builder (J ('Class "org.apache.spark.sql.SparkSession$Builder"))+ deriving Coercible++builder :: IO Builder+builder = [java| org.apache.spark.sql.SparkSession.builder() |]++config :: Builder -> SparkConf -> IO Builder+config b sc = [java| $b.config($sc) |]++sparkContext :: SparkSession -> IO SparkContext+sparkContext ss =+ [java| new org.apache.spark.api.java.JavaSparkContext($ss.sparkContext()) |]++getOrCreate :: Builder -> IO SparkSession+getOrCreate b = [java| $b.getOrCreate() |]
+ src/Language/Scala/Tuple.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StaticPointers #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Language.Scala.Tuple where++import Control.Distributed.Closure.TH+import Language.Java++data Tuple2 a b = Tuple2 a b+ deriving (Show, Eq)++withStatic [d|++ instance (Interpretation a, Interpretation b) =>+ Interpretation (Tuple2 a b) where+ type Interp (Tuple2 a b) =+ 'Class "scala.Tuple2" <> '[Interp a, Interp b]++ instance (Reify a, Reify b) =>+ Reify (Tuple2 a b) where+ reify jobj = do+ ja <- call jobj "_1" []+ jb <- call jobj "_2" []+ Tuple2 <$> (reify $ unsafeCast (ja :: JObject))+ <*> (reify $ unsafeCast (jb :: JObject))++ instance (Reflect a, Reflect b) =>+ Reflect (Tuple2 a b) where+ reflect (Tuple2 a b) = do+ ja <- reflect a+ jb <- reflect b+ generic <$> new [coerce $ upcast ja, coerce $ upcast jb]+ |]
src/main/java/Helper.java view
@@ -5,8 +5,9 @@ import org.apache.spark.api.java.function.*; import org.apache.spark.ml.feature.*; import org.apache.spark.mllib.clustering.*;+import org.apache.spark.mllib.linalg.SparseVector; import org.apache.spark.mllib.linalg.Vector;-import org.apache.spark.sql.DataFrame;+import org.apache.spark.sql.Dataset; import org.apache.spark.sql.SQLContext; import org.apache.spark.sql.Row; import org.apache.spark.sql.RowFactory;@@ -32,16 +33,7 @@ return res; } - public static DataFrame toDF(SQLContext ctx, JavaRDD<Row> rdd, String col1, String col2) {- StructType st =- new StructType().add(col1, DataTypes.LongType)- .add(col2, DataTypes.StringType);-- DataFrame df = ctx.createDataFrame(rdd, st);- return df;- }-- public static JavaRDD<Row> fromDF(DataFrame df, String col1, String col2) {+ public static JavaRDD<Row> fromDF(Dataset<Row> df, String col1, String col2) { return df.select(col1, col2).toJavaRDD(); } @@ -49,7 +41,7 @@ JavaPairRDD<Long, Vector> res = rows.mapToPair( new PairFunction<Row, Long, Vector>() { public Tuple2<Long, Vector> call(Row r) {- return new Tuple2<Long, Vector>((Long) r.get(0), (Vector) r.get(1));+ return new Tuple2<Long, Vector>((Long) r.get(0), SparseVector.fromML((org.apache.spark.ml.linalg.SparseVector) r.get(1)).compressed()); } }); return res.cache();
src/main/java/io/tweag/sparkle/function/HaskellFlatMapFunction.java view
@@ -10,7 +10,7 @@ this.clos = clos; } - public Iterable<R> call(T value) throws Exception {+ public java.util.Iterator<R> call(T value) throws Exception { return Sparkle.apply(clos, value); } }
+ src/main/java/io/tweag/sparkle/function/HaskellMapPartitionsFunction.java view
@@ -0,0 +1,18 @@+package io.tweag.sparkle.function;++import org.apache.spark.api.java.function.*;+import io.tweag.sparkle.Sparkle;+import java.util.Iterator;++public class HaskellMapPartitionsFunction<T, U> implements MapPartitionsFunction<T, U> {+ public final byte[] clos;++ public HaskellMapPartitionsFunction(final byte[] clos) {+ this.clos = clos;+ }++ @Override+ public Iterator<U> call(Iterator<T> input) throws Exception {+ return Sparkle.apply(clos, input);+ }+}
+ src/main/java/io/tweag/sparkle/function/HaskellReduceFunction.java view
@@ -0,0 +1,18 @@+package io.tweag.sparkle.function;++import org.apache.spark.api.java.function.*;+import io.tweag.sparkle.Sparkle;+import java.util.Iterator;++public class HaskellReduceFunction<T> implements ReduceFunction<T> {+ public final byte[] clos;++ public HaskellReduceFunction(final byte[] clos) {+ this.clos = clos;+ }++ @Override+ public T call(T a, T b) throws Exception {+ return Sparkle.apply(clos, a, b);+ }+}