无法在Spark 2.x中覆盖CSV文件的Schema

时间:2017-04-25 11:10:48

标签: scala csv apache-spark apache-spark-sql spark-dataframe

我有一个CSV文件,test.csv

col
1
2
3
4

当我使用Spark阅读它时,它会获得正确的数据模式:

val df = spark.read.option("header", "true").option("inferSchema", "true").csv("test.csv")

df.printSchema
root
 |-- col: integer (nullable = true)

但是,当我覆盖CSV文件的schema并使inferSchema为false时,SparkSession会部分地获取自定义架构。

val df = spark.read.option("header", "true").option("inferSchema", "false").schema(StructType(List(StructField("custom", StringType, false)))).csv("test.csv")

df.printSchema
root
 |-- custom: string (nullable = true)

我的意思是只有列名(custom)和数据类型(StringType)被提取。但是,nullable部分被忽略,因为它仍在nullable = true,这是不正确的。

我无法理解这种行为。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:1)

我认为“inferSchema”属性很常见,适用于数据框中的所有元素。但是,如果我们想要更改特定元素的可空属性。

我们可以处理/设置类似的东西,

setNullableStateOfColumn(df,“col",false)

def setNullableStateOfColumn(df:DataFrame, cn: String, nullable: Boolean) : DataFrame = {

  // get schema
  val schema = df.schema
  // modify [[StructField] with name `cn`
  val newSchema = StructType(schema.map {
    case StructField( c, t, _, m) if c.equals(cn) => StructField( c, t, nullable = nullable, m)
    case y: StructField => y
  })
  // apply new schema
  df.sqlContext.createDataFrame( df.rdd, newSchema )
}

有一个类似的线程用于设置元素的可空属性

Change nullable property of column in spark dataframe

答案 1 :(得分:1)

请考虑documentation关于Parquet(一种流行的"大数据"存储格式)的摘录:

" Spark SQL支持读取和写入自动保留原始数据模式的Parquet文件。在编写Parquet文件时,出于兼容性原因,所有列都会自动转换为可为空。"

出于同样的原因,CSV的处理方式相同。

至于什么"兼容性原因"意味着,Nathan Marz在他的书 Big Data 中描述了理想的存储架构既有强类型的完整性,也有灵活的进化。换句话说,添加和删除字段应该很容易,而不会让分析爆炸。实木复合地板既有型又有弹性; CSV非常灵活。无论您做什么,Spark都可以通过使列可以为空而来表达灵活性。你可以辩论你是否喜欢这种方法。

一个SQL表有严格定义的模式,很难改变 - 所以Scott Ambler写了一篇关于如何重构它们的大book。实木复合地板和CSV不太严格。它们都适合于构建它们的范例,而Spark的方法是采用通常与“大数据”相关的自由主义方法。存储格式。