복붙노트

[SCALA] 스파크 SQL 중첩 withColumn

SCALA

스파크 SQL 중첩 withColumn

나는 그들 중 일부는 구조체되어있는 여러 열이있는 DataFrame 있습니다. 이 같은

root
 |-- foo: struct (nullable = true)
 |    |-- bar: string (nullable = true)
 |    |-- baz: string (nullable = true)
 |-- abc: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- def: struct (nullable = true)
 |    |    |    |-- a: string (nullable = true)
 |    |    |    |-- b: integer (nullable = true)
 |    |    |    |-- c: string (nullable = true)

내가 바즈의 기능 바즈 대체 할 수있는 열 바즈에 UserDefinedFunction을 적용 할,하지만 할 방법을 알아낼 수 없습니다. 여기에서 원하는 출력의 예 (주의를 int 지금 바즈가 있음)이며

root
 |-- foo: struct (nullable = true)
 |    |-- bar: string (nullable = true)
 |    |-- baz: int (nullable = true)
 |-- abc: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- def: struct (nullable = true)
 |    |    |    |-- a: string (nullable = true)
 |    |    |    |-- b: integer (nullable = true)
 |    |    |    |-- c: string (nullable = true)

DataFrame.withColumn는 최고 수준의 열을하지만 중첩 된 열에서 작동 것 같습니다. 나는이 문제에 대한 스칼라를 사용하고 있습니다.

이와 캔 누군가의 도움이 나를?

감사

해결법

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

    1.쉽게 그, 그냥 예를 들어, 중첩 된 구조를 선택하는 점을 사용하여 "foo.baz을"$ :

    쉽게 그, 그냥 예를 들어, 중첩 된 구조를 선택하는 점을 사용하여 "foo.baz을"$ :

    case class Foo(bar:String,baz:String)
    case class Record(foo:Foo)
    
    val df = Seq(
       Record(Foo("Hi","There"))
    ).toDF()
    
    
    df.printSchema
    
    root
     |-- foo: struct (nullable = true)
     |    |-- bar: string (nullable = true)
     |    |-- baz: string (nullable = true)
    
    
    val myUDF = udf((s:String) => {
     // do something with s 
      s.toUpperCase
    })
    
    
    df
    .withColumn("udfResult",myUDF($"foo.baz"))
    .show
    
    +----------+---------+
    |       foo|udfResult|
    +----------+---------+
    |[Hi,There]|    THERE|
    +----------+---------+
    

    기존 구조체 foo는에 UDF의 결과를 추가하려는 경우, 즉 얻을 수 있습니다 :

    root
     |-- foo: struct (nullable = false)
     |    |-- bar: string (nullable = true)
     |    |-- baz: string (nullable = true)
     |    |-- udfResult: string (nullable = true)
    

    두 가지 옵션이 있습니다 :

    withColumn과 :

    df
    .withColumn("udfResult",myUDF($"foo.baz"))
    .withColumn("foo",struct($"foo.*",$"udfResult"))
    .drop($"udfResult")
    

    선택과 :

    df
    .select(struct($"foo.*",myUDF($"foo.baz").as("udfResult")).as("foo"))
    

    편집하다: 는 UDF의 결과와 구조체의 기존 속성을 교체 : 불행하게도,이 작동하지 않습니다 :

    df
    .withColumn("foo.baz",myUDF($"foo.baz")) 
    

    그러나 다음과 같이 수행 할 수 있습니다 :

    // get all columns except foo.baz
    val structCols = df.select($"foo.*")
        .columns
        .filter(_!="baz")
        .map(name => col("foo."+name))
    
    df.withColumn(
        "foo",
        struct((structCols:+myUDF($"foo.baz").as("baz")):_*)
    )
    
  2. from https://stackoverflow.com/questions/44831789/spark-sql-nested-withcolumn by cc-by-sa and MIT license