我是Scala和Spark的新手,所以我希望有人可以解释为什么aggregateByKey在抽象类中时无法编译。这是我能提出的最简单的例子:
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
abstract class AbstractKeyCounter[K] {
def keyValPairs(): RDD[(K, String)]
def processData(): RDD[(K, Int)] = {
keyValPairs().aggregateByKey(0)(
(count, key) => count + 1,
(count1, count2) => count1 + count2
)
}
}
class StringKeyCounter extends AbstractKeyCounter[String] {
override def keyValPairs(): RDD[(String, String)] = {
val sc = new SparkContext(new SparkConf().setMaster("local").setAppName("counter"))
val data = sc.parallelize(Array("foo=A", "foo=A", "foo=A", "foo=B", "bar=C", "bar=D", "bar=D"))
data.map(_.split("=")).map(v => (v(0), v(1)))
}
}
给出了:
Error:(11, 19) value aggregateByKey is not a member of org.apache.spark.rdd.RDD[(K, String)]
keyValPairs().aggregateByKey(0)(
^
如果我改为使用单个具体类,它会编译并成功运行:
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
class StringKeyCounter {
def processData(): RDD[(String, Int)] = {
val sc = new SparkContext(new SparkConf().setMaster("local").setAppName("counter"))
val data = sc.parallelize(Array("foo=A", "foo=A", "foo=A", "foo=B", "bar=C", "bar=D", "bar=D"))
val keyValPairs = data.map(_.split("=")).map(v => (v(0), v(1)))
keyValPairs.aggregateByKey(0)(
(count, key) => count + 1,
(count1, count2) => count1 + count2
)
}
}
我错过了什么?
答案 0 :(得分:3)
如果你改变:
abstract class AbstractKeyCounter[K] {
要:
abstract class AbstractKeyCounter[K : ClassTag] {
这将编译。
<强>为什么强>? aggregateByKey
是PairRDDFunctions
的一种方法(您的RDD
被隐式转换为该类),其具有以下签名:
class PairRDDFunctions[K, V](self: RDD[(K, V)])
(implicit kt: ClassTag[K], vt: ClassTag[V], ord: Ordering[K] = null)
这意味着它的构造函数需要类型为ClassTag[K]
和vt: ClassTag[V]
的隐式值。您的抽象类不知道K是什么,因此无法提供匹配的隐式值。这意味着隐式转换为PairRDDFunctions
“失败”(编译器不执行转换),因此无法找到方法aggregateByKey
。
添加[K : ClassTag]
是向抽象类构造函数添加隐式参数implicit kt: ClassTag[K]
的简写,然后由编译器使用它并传递给PairRDDFunctions
的构造函数。
有关ClassTag的更多信息以及它们有用的内容,请参阅this good article。