Scala apachespark中的Case类相等

Scala apachespark中的Case类相等,scala,apache-spark,pattern-matching,rdd,case-class,Scala,Apache Spark,Pattern Matching,Rdd,Case Class,为什么Spark中的模式匹配与Scala中的工作方式不同?见下面的例子。。。函数f()尝试在类上进行模式匹配,该类在Scala REPL中工作,但在Spark中失败,并导致所有“?”f2()是一种变通方法,它使用.isInstanceOf()在Spark中获得所需的结果,但我知道这在Scala中是不好的形式 在Spark中,任何关于模式匹配的正确方法的帮助都将不胜感激 abstract class a extends Serializable {val a: Int} case class b(

为什么Spark中的模式匹配与Scala中的工作方式不同?见下面的例子。。。函数
f()
尝试在类上进行模式匹配,该类在Scala REPL中工作,但在Spark中失败,并导致所有“?”
f2()
是一种变通方法,它使用
.isInstanceOf()
在Spark中获得所需的结果,但我知道这在Scala中是不好的形式

在Spark中,任何关于模式匹配的正确方法的帮助都将不胜感激

abstract class a extends Serializable {val a: Int}
case class b(a: Int) extends a 
case class bNull(a: Int=0) extends a 

val x: List[a] = List(b(0), b(1), bNull())
val xRdd = sc.parallelize(x)
尝试在Scala REPL中工作但在Spark中失败的模式匹配

def f(x: a) = x match {
    case b(n) => "b"
    case bNull(n) => "bnull"
    case _ => "???"
}
在Spark中运行的变通方法,但形式不好(我认为)

查看结果

xRdd.map(f).collect                   //does not work in Spark
                                      // result: Array("???", "???", "???")
xRdd.map(f2).collect                  // works in Spark
                                      // resut: Array("b", "b", "bnull")
x.map(f(_))                           // works in Scala REPL    
                                      // result: List("b", "b", "bnull")
使用的版本。。。 火花结果在火花壳中运行(AWS EMR-4.3上的火花1.6)
SBT 0.13.9(Scala 2.10.5)中的Scala REPL这是Spark REPL的一个已知问题。您可以在中找到更多详细信息。它影响Spark REPL中的多个操作,包括
成对DDS
上的大多数转换。例如:

case class Foo(x: Int)

val foos = Seq(Foo(1), Foo(1), Foo(2), Foo(2))
foos.distinct.size
// Int = 2

val foosRdd = sc.parallelize(foos, 4)
foosRdd.distinct.count
// Long = 4  

foosRdd.map((_, 1)).reduceByKey(_ + _).collect
// Array[(Foo, Int)] = Array((Foo(1),1), (Foo(1),1), (Foo(2),1), (Foo(2),1))

foosRdd.first == foos.head
// Boolean = false

Foo.unapply(foosRdd.first) == Foo.unapply(foos.head)
// Boolean = true
更糟糕的是,结果取决于数据分布:

sc.parallelize(foos, 1).distinct.count
// Long = 2

sc.parallelize(foos, 1).map((_, 1)).reduceByKey(_ + _).collect
// Array[(Foo, Int)] = Array((Foo(2),2), (Foo(1),2))
您可以做的最简单的事情是在REPL外部定义和打包所需的case类。使用
spark submit
直接提交的任何代码也应该有效

在Scala 2.11+中,您可以使用
粘贴-raw
直接在REPL中创建包

scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package bar

case class Bar(x: Int)


// Exiting paste mode, now interpreting.

scala> import bar.Bar
import bar.Bar

scala> sc.parallelize(Seq(Bar(1), Bar(1), Bar(2), Bar(2))).distinct.collect
res1: Array[bar.Bar] = Array(Bar(1), Bar(2))

这是Spark REPL的已知问题。您可以在中找到更多详细信息。它影响Spark REPL中的多个操作,包括
成对DDS
上的大多数转换。例如:

case class Foo(x: Int)

val foos = Seq(Foo(1), Foo(1), Foo(2), Foo(2))
foos.distinct.size
// Int = 2

val foosRdd = sc.parallelize(foos, 4)
foosRdd.distinct.count
// Long = 4  

foosRdd.map((_, 1)).reduceByKey(_ + _).collect
// Array[(Foo, Int)] = Array((Foo(1),1), (Foo(1),1), (Foo(2),1), (Foo(2),1))

foosRdd.first == foos.head
// Boolean = false

Foo.unapply(foosRdd.first) == Foo.unapply(foos.head)
// Boolean = true
更糟糕的是,结果取决于数据分布:

sc.parallelize(foos, 1).distinct.count
// Long = 2

sc.parallelize(foos, 1).map((_, 1)).reduceByKey(_ + _).collect
// Array[(Foo, Int)] = Array((Foo(2),2), (Foo(1),2))
您可以做的最简单的事情是在REPL外部定义和打包所需的case类。使用
spark submit
直接提交的任何代码也应该有效

在Scala 2.11+中,您可以使用
粘贴-raw
直接在REPL中创建包

scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package bar

case class Bar(x: Int)


// Exiting paste mode, now interpreting.

scala> import bar.Bar
import bar.Bar

scala> sc.parallelize(Seq(Bar(1), Bar(1), Bar(2), Bar(2))).distinct.collect
res1: Array[bar.Bar] = Array(Bar(1), Bar(2))

谢谢你!我看到有人提到模式匹配在火花壳中不起作用,但没有细节。。。你是说如果我在jar中定义我的案例类,我就能在REPL中对它们进行模式匹配?再次感谢!确切地定义外部,构建jar,包括在
类路径中
并导入。感谢zero323!我看到有人提到模式匹配在火花壳中不起作用,但没有细节。。。你是说如果我在jar中定义我的案例类,我就能在REPL中对它们进行模式匹配?再次感谢!确切地在外部定义、构建jar、包含在类路径中并导入。