복붙노트

[SCALA] 아파치 스파크의 케이스 클래스 평등

SCALA

아파치 스파크의 케이스 클래스 평등

왜 스파크의 패턴 매칭은 스칼라에서와 동일하게 작동하지 않는 이유는 무엇입니까? 스칼라 REPL에서 작동하지만 모두 스파크 및 결과에 실패 클래스의 패턴 일치에 시도) (예를 아래에 ... 함수 F를 참조하십시오 "???". F2는 () .isInstanceOf ()을 사용하여 불꽃으로 원하는 결과를 유도 할 수있는 해결책이지만, 그 스칼라 나쁜 형태로 이해한다.

불꽃이 시나리오에서 올바른 방법을 패턴 매칭에 어떤 도움을 크게 감상 할 수있다.

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)

스칼라 REPL에서 작동하지만 스파크에 실패 패턴 매칭에서 시도

def f(x: a) = x match {
    case b(n) => "b"
    case bNull(n) => "bnull"
    case _ => "???"
}

스파크으로 작동하지만, 나쁜 형태의 해결 방법 (내 생각)

def f2(x: a) = {
    if (x.isInstanceOf[b]) {
        "b"
    } else if (x.isInstanceOf[bNull]) {
        "bnull"
    } else {
        "???"
    }
}

결과보기

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에 1.6 스파크 EMR-4.3) SBT의 0.13.9에서 스칼라 REPL (2.10.5 스칼라)

해결법

  1. ==============================

    1.이 스파크 REPL 알려진 문제입니다. 당신은 SPARK-2620에서 자세한 내용을 확인할 수 있습니다. 그것은 PairwiseRDDs에 변환의 대부분을 포함 스파크 REPL에서 여러 작업에 영향을 미칩니다. 예를 들면 :

    이 스파크 REPL 알려진 문제입니다. 당신은 SPARK-2620에서 자세한 내용을 확인할 수 있습니다. 그것은 PairwiseRDDs에 변환의 대부분을 포함 스파크 REPL에서 여러 작업에 영향을 미칩니다. 예를 들면 :

    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 외부에서 필요한 경우 클래스를 정의 및 패키지하는 것입니다. 모든 코드는 직접 불꽃을 제출하여 제출뿐만 아니라 작동합니다.

    스칼라에서는 붙여 넣기 -raw와 REPL에서 직접 패키지를 만들 수 있습니다 2.11+.

    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))
    
  2. from https://stackoverflow.com/questions/35301998/case-class-equality-in-apache-spark by cc-by-sa and MIT license