如何在rdd中放置一个case类并让它像一个元组(对)?

时间:2016-01-20 15:42:13

标签: scala apache-spark tuples rdd

比方说,我有一个简单的案例类

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>

2 个答案:

答案 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)