我正在尝试在Clojure中重写Spark Structured Streaming示例。
该示例使用Scala编写如下:
(ns flambo-example.streaming-example
(:import [org.apache.spark.sql Encoders SparkSession Dataset Row]
[org.apache.spark.sql.functions]
))
(def spark
(->
(SparkSession/builder)
(.appName "sample")
(.master "local[*]")
.getOrCreate)
)
(def lines
(-> spark
.readStream
(.format "socket")
(.option "host" "localhost")
(.option "port" 9999)
.load
)
)
(def words
(-> lines
(.as (Encoders/STRING))
(.flatMap #(clojure.string/split % #" " ))
))
以上代码会导致以下异常。
;;由java.lang.IllegalArgumentException引起 ;;找不到匹配的方法:class的flatMap ;; org.apache.spark.sql.Dataset
如何避免错误?
答案 0 :(得分:1)
您必须遵循签名。 Java Dataset
API提供了Dataset.flatMap
的两个实现,其中一个实现了scala.Function1
def flatMap[U](func: (T) ⇒ TraversableOnce[U])(implicit arg0: Encoder[U]): Dataset[U]
和第二个采用Spark自己的o.a.s.api.java.function.FlatMapFunction
def flatMap[U](f: FlatMapFunction[T, U], encoder: Encoder[U]): Dataset[U]
前者对你来说相当无用,但你应该能够使用后者。可以使用RDD
访问的flambo
API flambo.api/fn
uses macros to create Spark friendly adapters - 我不确定这些是否可以直接与Datasets
一起使用,但您应该能够如果需要,请调整它们。
由于您不能依赖隐式Encoders
,因此您还必须提供与返回类型匹配的显式编码器。
总的来说,你需要一些东西:
(def words
(-> lines
(.as (Encoders/STRING))
(.flatMap f e)
))
其中f
实现FlatMapFunction
而e
是Encoder
。一个示例实现:
(def words
(-> lines
(.as (Encoders/STRING))
(.flatMap
(proxy [FlatMapFunction] []
(call [s] (.iterator (clojure.string/split s #" "))))
(Encoders/STRING))))
但我想有可能找到一个更好的。
在实践中,我会避免键入Dataset
,并专注于DataFrame
(Dataset[Row]
)。