【问题标题】:Does the dataframe know the type of column?数据框是否知道列的类型?
【发布时间】:2019-06-10 02:00:42
【问题描述】:

看了一些技术文章,据说dataframe只知道列名不知道类型。但是,亲自调用dataframe的`printSchema函数后,可以打印出列的名称和类型。我对此非常怀疑。我期待着你的回答。

例子:

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

对于这个例子,dataframe schema 的 age 类型是 integer , dataset schema 的 age 类型是 long , class Person 的 age 类型是 long 。

【问题讨论】:

标签: apache-spark dataframe apache-spark-sql dataset


【解决方案1】:

这取决于您正在阅读的文件类型。

如果是没有标题的 CSV 文件,则需要使用 schema 提供列名和数据类型。

这是一个带有标题的 CSV 文件,那么您需要在读取文件时使用“inferSchema”->“true”作为选项。此选项自动推断架构和数据类型。但是,数据类型是根据实际数据的前几条记录自动驱动的。

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

出于任何原因,如果您的列的前几条记录具有整数值,而其他记录具有字符串,那么您将遇到问题,因此,明确提供架构始终是最佳实践。

您的代码按预期工作。

下面的语句根据数据 Seq(("aa",1),("bb",2)) 自动推断年龄的数据类型为 Int

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

但是,当您将 Dataframe 转换为 Dataset 时

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

在这里,您将转换为“年龄”字段具有 Long 数据类型的 Person,因此,您看到的是 Long 和预期的一样。请注意,从 Int 自动转换为 Long 是由 Scala(向上转换)而不是 Spark 完成的。

希望这可以澄清!

下面的链接很好地了解了如何提供复杂的架构。希望这能给你更多的想法。

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

谢谢

【讨论】:

  • 非常感谢您的回答。请给我你的建议,让我回答。
【解决方案2】:

在您使用rdd.toDF("name", "age") 的第一个示例中,您没有显式地为 DataFrame 提供架构。而且,DataFrames 实际上只是 DataSet[Row]。因此,Spark 会根据数据(int 基于12)选择可能的最佳数据类型。

在第二个示例中,您创建了一个 DataSet,它根据提供的架构保留数据类型。所以:

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

创建一个DataSet[Person] 以保持指定的架构不变。

【讨论】:

  • 非常感谢您的回答。请给我你的建议,让我回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-23
相关资源
最近更新 更多