阻止DataFrame.partitionBy()从架构中删除分区列

Mic*_*ael 15 apache-spark spark-dataframe

我正在按如下方式对DataFrame进行分区:

df.write.partitionBy("type", "category").parquet(config.outpath)
Run Code Online (Sandbox Code Playgroud)

代码给出了预期的结果(即按类型和类别划分的数据).但是,"type"和"category"列将从数据/模式中删除.有没有办法防止这种行为?

Iva*_*ali 13

我可以想到一个解决方法,这是相当蹩脚的,但有效.

import spark.implicits._

val duplicated = df.withColumn("_type", $"type").withColumn("_category", $"category")
duplicated.write.partitionBy("_type", "_category").parquet(config.outpath)
Run Code Online (Sandbox Code Playgroud)

我正在回答这个问题,希望有人能得到比我更好的答案或解释(如果OP找到了更好的解决方案),因为我有同样的问题.

  • 其实看起来并不蹩脚.似乎是给出`partitionBy()`行为的最佳方法. (3认同)

Sta*_*ger 6

我想在这里添加更多上下文,并为需要它的人提供 PySpark 代码而不是 Scala。如果您想保留分区变量(细节很重要),则需要小心读取分区数据帧的方式。让我们从编写这样的分区数据帧开始:

df.write.mode("overwrite").partitionBy("Season").parquet("partitioned_parquet/")
Run Code Online (Sandbox Code Playgroud)

要将整个数据帧读回包含分区变量...

path = "partitioned_parquet/"
parquet = spark.read.parquet(path)
parquet.show()
Run Code Online (Sandbox Code Playgroud)

结果:

+-----+------+
|Value|Season|
+-----+------+
|   71|  2010|
|   77|  2010|
|   83|  2010|
|   54|  2010|
|  100|  2010|
+-----+------+
only showing top 5 rows
Run Code Online (Sandbox Code Playgroud)

请注意,如果您在路径名末尾包含 *,分区变量将被删除

path = "partitioned_parquet/*"
parquet = spark.read.parquet(path)
parquet.show(5)
Run Code Online (Sandbox Code Playgroud)

结果:

+-----+
|Value|
+-----+
|   71|
|   77|
|   83|
|   54|
|  100|
+-----+
only showing top 5 rows
Run Code Online (Sandbox Code Playgroud)

现在,如果你要读只有部分的分区数据框中的,您需要使用此方法,以保持你的分区变量(在这种情况下,“季”)。

path = "partitioned_parquet/"
dataframe = spark.read.option("basePath", path).parquet(path+'Season=2010/',\
                                                                path+'Season=2011/', \
                                                                path+'Season=2012/')
dataframe.show(5)
Run Code Online (Sandbox Code Playgroud)

结果:

+-----+------+
|Value|Season|
+-----+------+
|   71|  2010|
|   77|  2010|
|   83|  2010|
|   54|  2010|
|  100|  2010|
+-----+------+
only showing top 5 rows
Run Code Online (Sandbox Code Playgroud)

希望对大家有所帮助!


Rob*_*tty 5

总的来说,伊凡的回答是一个很好的结论。但...

如果您严格按照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将自动从路径中提取分区信息。

例:

     val dataset = spark
      .read
      .format("parquet")
      .option("basePath", hdfsInputBasePath)
      .load(hdfsInputPath)
Run Code Online (Sandbox Code Playgroud)