схема приведения фрейма данных в Spark и Scala

Я хочу преобразовать схему фрейма данных, чтобы изменить тип некоторых столбцов с помощью Spark и Scala.

В частности, я пытаюсь использовать функцию [U], описание которой гласит: «Возвращает новый набор данных, в котором каждая запись сопоставлена ​​с указанным типом. Метод, используемый для сопоставления столбцов, зависит от типа U "

В принципе это именно то, что я хочу, но не могу заставить его работать.

Вот простой пример, взятый из https://github.com/apache/spark/blob/master/sql/core/src/test/scala/org/apache/spark/sql/DatasetSuite.scala



    // definition of data
    val data = Seq(("a", 1), ("b", 2)).toDF("a", "b")

Как и ожидалось, схема данных:


    root
     |-- a: string (nullable = true)
     |-- b: integer (nullable = false)
    

Я хотел бы преобразовать столбец «b» в Double. Поэтому я пробую следующее:



    import session.implicits._;

    println(" --------------------------- Casting using (String Double)")

    val data_TupleCast=data.as[(String, Double)]
    data_TupleCast.show()
    data_TupleCast.printSchema()

    println(" --------------------------- Casting using ClassData_Double")

    case class ClassData_Double(a: String, b: Double)

    val data_ClassCast= data.as[ClassData_Double]
    data_ClassCast.show()
    data_ClassCast.printSchema()

Насколько я понимаю определение as [u], новые DataFrames должны иметь следующую схему


    root
     |-- a: string (nullable = true)
     |-- b: double (nullable = false)

Но на выходе


     --------------------------- Casting using (String Double)
    +---+---+
    |  a|  b|
    +---+---+
    |  a|  1|
    |  b|  2|
    +---+---+

    root
     |-- a: string (nullable = true)
     |-- b: integer (nullable = false)

     --------------------------- Casting using ClassData_Double
    +---+---+
    |  a|  b|
    +---+---+
    |  a|  1|
    |  b|  2|
    +---+---+

    root
     |-- a: string (nullable = true)
     |-- b: integer (nullable = false)

который показывает, что столбец «b» не удваивается.

Есть намеки на то, что я делаю не так?

Кстати: я знаю предыдущий пост «Как изменить типы столбцов в DataFrame Spark SQL?» (см. Как изменить типы столбцов в DataFrame Spark SQL? ). Я знаю, что могу изменять тип столбцов по одному, но я ищу более общее решение, которое изменяет схему всех данных за один раз (и я пытаюсь понять Spark в процессе).


person Massimo Paolucci    schedule 25.10.2016    source источник
comment
Я не думаю, что вы можете - as[U] API не изменяет фактические типы, он просто предоставляет типизированный API для обработки набора данных; U должен соответствовать фактическим типам, а изменение фактических типов может быть выполнено только с помощью преобразований, таких как Column.cast, как описано в вопросе, который вы связали.   -  person Tzach Zohar    schedule 25.10.2016


Ответы (1)


Ну, поскольку функции связаны, а Spark выполняет ленивую оценку, он фактически действительно изменяет схему всех данных за один раз, даже если вы пишете это как изменение одного столбца за раз, например:

import spark.implicits._

df.withColumn("x", 'x.cast(DoubleType)).withColumn("y", 'y.cast(StringType))...

В качестве альтернативы, я думаю, вы могли бы использовать map, чтобы выполнить кастинг за один раз, например:

df.map{t => (t._1, t._2.asInstanceOf[Double], t._3.asInstanceOf[], ...)}
person Glennie Helles Sindholt    schedule 25.10.2016
comment
Спасибо за предложения, они очень похожи на другие решения, которые я нашел на SO. Кроме того, они очень соответствуют решениям, которые я собираюсь принять. Тем не менее, было бы очень удобно использовать как [u]. Мне также интересно, стоит ли мне трюк с кодировщиками, но тогда я не понимаю, почему, если один использует (String, Int), то кодеры не нужны. - person Massimo Paolucci; 25.10.2016