Знает ли фрейм данных тип столбца? - PullRequest
0 голосов
/ 16 января 2019

После прочтения некоторых технических статей говорят, что датафрейм знает только имя столбца, но не его тип. Однако после личного вызова функции printSchema для dataframe можно напечатать имя и тип столбца. Я очень сомневаюсь по этому поводу. Я с нетерпением жду вашего ответа.

пример:

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.SparkSession

case class Person(name:String,age:Long)
object DS {
  def main(args: Array[String]): Unit = {
    val config = new SparkConf().setAppName("sparkSql").setMaster("local[*]")
    val sc = new SparkContext(config)
    val spark = SparkSession.builder().config(config).getOrCreate()
    val seq = Seq(("aa",1),("bb",2))
    import spark.implicits._
    val rdd = sc.makeRDD(seq)
    val df = rdd.toDF("name","age")
    val ds = rdd.map(line =>{Person(line._1,line._2)}).toDS()

    println("dataframe schema:")
    df.printSchema()
/*
    dataframe schema:
      root
    |-- name: string (nullable = true)
    |-- age: integer (nullable = true)
*/
    println("dataset schema:")
    ds.printSchema()
/*
    dataset schema:
      root
    |-- name: string (nullable = true)
    |-- age: long (nullable = true)
*/
  }
}

IMG

Для этого примера , возрастной тип схемы данных - целочисленный, возрастной тип схемы набора данных - длинный, возрастной класс класса Person - длинный.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

В первом примере, где вы используете rdd.toDF("name", "age"), вы явно не предоставляете схему для DataFrame. И DataFrames на самом деле просто DataSet[Row]. Следовательно, Spark выбирает наилучший из возможных типов данных на основе данных (int на основе 1 и 2).

Во втором примере вы создаете DataSet, который сохраняет тип данных на основе предоставленной схемы. Итак:

val ds = rdd.map(line => Person(line._1,line._2) ).toDS()

Создает DataSet[Person], который сохраняет указанную схему без изменений.

0 голосов
/ 16 января 2019

Зависит от того, какой тип файла вы читаете.

Если это CSV-файл без заголовка, вам необходимо указать имя столбца и тип данных, используя схему.

Это CSV-файл с заголовком, поэтому вам нужно использовать "inferSchema" -> "true" в качестве опции при чтении файла. Эта опция автоматически выводит схему и типы данных. Однако тип данных автоматически определяется на основе первых нескольких записей фактических данных.

val df = spark.read.options(Map("inferSchema"->"true","delimiter"->"|","header"->"true")).csv(filePath)

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

Ваш код работает как положено.

Оператор ниже автоматически выводит тип данных Int для возраста на основе данных Seq (("aa", 1), ("bb", 2))

val df = rdd.toDF("name","age")

Однако при преобразовании Dataframe в набор данных

val ds = rdd.map(line =>{Person(line._1,line._2)}).toDS()

Здесь вы конвертируете в Person, который имеет тип данных Long для поля age, следовательно, вы видите его длинным, как и ожидалось. Обратите внимание, что автоматическое преобразование из Int в Long выполняется Scala (повышенный состав), а не Spark.

Надеюсь, это прояснит !!

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

https://medium.com/@mrpowers/adding-structtype-columns-to-spark-dataframes-b44125409803

Спасибо

...