我有一个如下的数据框。
itemName, itemCategory
Name1, C0
Name2, C1
Name3, C0
我想将此数据框保存为分区镶木地板文件:
df.write.mode("overwrite").partitionBy("itemCategory").parquet(path)
对于这个数据帧,当我读回数据时,它将具有String itemCategory
的数据类型。
但有时,我的其他租户的数据框如下所示。
itemName, itemCategory
Name1, 0
Name2, 1
Name3, 0
在这种情况下,在作为分区写入后,当回读时,结果数据帧将具有Int,数据类型为itemCategory
。
Parquet文件具有描述数据类型的元数据。如何指定分区的数据类型,以便将其作为String而不是Int?
读回答案 0 :(得分:0)
当您按itemCategory
列进行分区时,此数据将存储在文件结构中,而不是实际的csv文件中。 Spark根据值推断数据类型,如果所有值都是整数,则列类型将为int。
一个简单的解决方案是在读取数据后将列转换为StringType
:
import spark.implicits._
df.withColumn("itemCategory", $"itemCategory".cast(StringType))
另一种选择是复制列本身。然后,其中一列将用于分区,因此将保存在文件结构中。但是,其他重复列将正常保存在镶木地板文件中。要复制,只需使用:
df.withColumn("itemCategoryCopy", $"itemCategory")
答案 1 :(得分:0)
如果将“ spark.sql.sources.partitionColumnTypeInference.enabled”设置为“ false”,spark将推断所有分区列为字符串。
在spark 2.0或更高版本中,您可以这样设置:
spark.conf.set("spark.sql.sources.partitionColumnTypeInference.enabled", "false")
在1.6中,像这样:
sqlContext.setConf("spark.sql.sources.partitionColumnTypeInference.enabled", "false")
缺点是,每次读取数据时都必须这样做,但至少可以正常工作。
答案 2 :(得分:0)
使用架构读取它:
import spark.implicits._
val path = "/tmp/test/input"
val source = Seq(("Name1", "0"), ("Name2", "1"), ("Name3", "0")).toDF("itemName", "itemCategory")
source.write.partitionBy("itemCategory").parquet(path)
spark.read.schema(source.schema).parquet(path).printSchema()
// will print
// root
// |-- itemName: string (nullable = true)
// |-- itemCategory: string (nullable = true)