我按如下方式对DataFrame进行分区:
df.write.partitionBy("type", "category").parquet(config.outpath)
代码给出了预期的结果(即按类型和类别划分的数据)。然而,"类型"和"类别"列将从数据/架构中删除。有没有办法防止这种行为?
答案 0 :(得分:12)
我可以想到一个解决方法,这个方法相当蹩脚,但有效。
import spark.implicits._
val duplicated = df.withColumn("_type", $"type").withColumn("_category", $"category")
duplicated.write.partitionBy("_type", "_category").parquet(config.outpath)
我回答这个问题,希望有人能得到比我更好的答案或解释(如果OP找到了更好的解决方案),因为我有同样的问题。
答案 1 :(得分:4)
总的来说,伊万的回答是一个很好的问题。但是...
如果你严格阅读和写入spark,你可以在阅读数据时使用basePath选项。
https://spark.apache.org/docs/2.2.0/sql-programming-guide.html#partition-discovery
通过将path / to / table传递给SparkSession.read.parquet或SparkSession.read.load,Spark SQL将自动从路径中提取分区信息。
示例:
GetTypeSymbol
答案 2 :(得分:0)
我想在这里添加更多上下文,并为需要它的人提供PySpark代码而不是Scala。如果要保留分区变量(细节很重要),则需要注意如何读取分区数据框。让我们首先编写一个这样的分区数据框:
df.write.mode("overwrite").partitionBy("Season").parquet("partitioned_parquet/")
要在包含分区变量的情况下重新读取整个数据框...
path = "partitioned_parquet/"
parquet = spark.read.parquet(path)
parquet.show()
结果:
+-----+------+
|Value|Season|
+-----+------+
| 71| 2010|
| 77| 2010|
| 83| 2010|
| 54| 2010|
| 100| 2010|
+-----+------+
only showing top 5 rows
请注意,如果在路径名的末尾添加*,则会删除分区变量。。
path = "partitioned_parquet/*"
parquet = spark.read.parquet(path)
parquet.show(5)
结果:
+-----+
|Value|
+-----+
| 71|
| 77|
| 83|
| 54|
| 100|
+-----+
only showing top 5 rows
现在,如果您只想读取分区数据帧的部分,则需要使用此方法来保留分区变量(在本例中为“ Season”)。
path = "partitioned_parquet/"
dataframe = spark.read.option("basePath", path).parquet(path+'Season=2010/',\
path+'Season=2011/', \
path+'Season=2012/')
dataframe.show(5)
结果:
+-----+------+
|Value|Season|
+-----+------+
| 71| 2010|
| 77| 2010|
| 83| 2010|
| 54| 2010|
| 100| 2010|
+-----+------+
only showing top 5 rows
希望对人们有帮助!