比方说,我有一个简单的案例类
case class Foo(k:String, v1:String, v2:String)
我是否可以通过这种方式将其识别为元组,而无需转换为元组,例如地图或keyBy步骤。
val rdd = sc.parallelize(List(Foo("k", "v1", "v2")))
// Swap values
rdd.mapValues(v => (v._2, v._1))
在这样的操作之后,我甚至不关心它是否会失去原来的案例类。我试过以下没有运气。我对Scala很新,我错过了什么吗?
case class Foo(k:String, v1:String, v2:String)
extends Tuple2[String, (String, String)](k, (v1, v2))
编辑:在上面的代码片段中,case类扩展了Tuple2,这不会产生RDD类和函数不像元组那样对待并允许PairRDDFunctions,例如mapValues,values,reduceByKey等所需的效果。 / p>
答案 0 :(得分:9)
由于多种原因,扩展TupleN
不是一个好主意,最好的一个原因是它被弃用了,而在2.11上甚至不可能用TupleN
来扩展Foo
类。即使你使-deprecation
成为非案例类,在2.11上使用RDD[Foo]
定义它也会显示:“警告:不推荐使用包scala中的类Tuple2继承:元组将成为最终的未来版本。“。
如果您关心的是使用方便,并且您不介意转换为元组的开销(几乎可以忽略不计),您可以使用{{1}提供的语法来丰富PairRDDFunctions
转换如下:
import org.apache.spark.rdd.{ PairRDDFunctions, RDD }
case class Foo(k: String, v1: String, v2: String)
implicit def fooToPairRDDFunctions[K, V]
(rdd: RDD[Foo]): PairRDDFunctions[String, (String, String)] =
new PairRDDFunctions(
rdd.map {
case Foo(k, v1, v2) => k -> (v1, v2)
}
)
然后:
scala> val rdd = sc.parallelize(List(Foo("a", "b", "c"), Foo("d", "e", "f")))
rdd: org.apache.spark.rdd.RDD[Foo] = ParallelCollectionRDD[6] at parallelize at <console>:34
scala> rdd.mapValues(_._1).first
res0: (String, String) = (a,b)
Foo
扩展Tuple2[String, (String, String)]
的版本不起作用的原因是RDD.rddToPairRDDFunctions
定位RDD[Tuple2[K, V]]
而RDD
的类型不协变参数,因此RDD[Foo]
不是RDD[Tuple2[K, V]]
。一个更简单的例子可能会更清楚:
case class Box[A](a: A)
class Foo(k: String, v: String) extends Tuple2[String, String](k, v)
class PairBoxFunctions(box: Box[(String, String)]) {
def pairValue: String = box.a._2
}
implicit def toPairBoxFunctions(box: Box[(String, String)]): PairBoxFunctions =
new PairBoxFunctions(box)
然后:
scala> Box(("a", "b")).pairValue
res0: String = b
scala> Box(new Foo("a", "b")).pairValue
<console>:16: error: value pairValue is not a member of Box[Foo]
Box(new Foo("a", "b")).pairValue
^
但如果你让Box
协变......
case class Box[+A](a: A)
class Foo(k: String, v: String) extends Tuple2[String, String](k, v)
class PairBoxFunctions(box: Box[(String, String)]) {
def pairValue: String = box.a._2
}
implicit def toPairBoxFunctions(box: Box[(String, String)]): PairBoxFunctions =
new PairBoxFunctions(box)
......一切都很好:
scala> Box(("a", "b")).pairValue
res0: String = b
scala> Box(new Foo("a", "b")).pairValue
res1: String = b
但是,你不能让RDD
协变,所以定义你自己的隐式转换以添加语法是你最好的选择。就个人而言,我可能会选择明确地进行转换,但这是对隐式转换的相对不可靠的使用。
答案 1 :(得分:0)
不确定我的问题是否正确,但假设您有一个案例类
import org.apache.spark.rdd.RDD
case class DataFormat(id: Int, name: String, value: Double)
val data: Seq[(Int, String, Double)] = Seq(
(1, "Joe", 0.1),
(2, "Mike", 0.3)
)
val rdd: RDD[DataFormat] = (
sc.parallelize(data).map(x=>DataFormat(x._1, x._2, x._3))
)
// Print all data
rdd.foreach(println)
// Print only names
rdd.map(x=>x.name).foreach(println)