我有一个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
,这是不正确的。
我无法理解这种行为。任何帮助表示赞赏!
答案 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 )
}
有一个类似的线程用于设置元素的可空属性
答案 1 :(得分:1)
请考虑documentation关于Parquet(一种流行的"大数据"存储格式)的摘录:
" Spark SQL支持读取和写入自动保留原始数据模式的Parquet文件。在编写Parquet文件时,出于兼容性原因,所有列都会自动转换为可为空。"
出于同样的原因,CSV的处理方式相同。
至于什么"兼容性原因"意味着,Nathan Marz在他的书 Big Data 中描述了理想的存储架构既有强类型的完整性,也有灵活的进化。换句话说,添加和删除字段应该很容易,而不会让分析爆炸。实木复合地板既有型又有弹性; CSV非常灵活。无论您做什么,Spark都可以通过使列可以为空而来表达灵活性。你可以辩论你是否喜欢这种方法。
一个SQL表有严格定义的模式,很难改变 - 所以Scott Ambler写了一篇关于如何重构它们的大book。实木复合地板和CSV不太严格。它们都适合于构建它们的范例,而Spark的方法是采用通常与“大数据”相关的自由主义方法。存储格式。