我正在用分区实木复合地板写一个大表(约1.2b行),我使用状态(如美国状态)作为分区键。问题是存在大量的空状态值。该表通常是按状态查询的,因此具有大的具有空状态的分区不是问题,但是我在更高效地生成表方面遇到了麻烦。
我尝试用非空状态创建表,然后插入空值,但是据我所知,所有空值仍然只是放在一个大分区中,并因此发送给一个工人。
如果有一种方法可以插入特定的分区,那就太好了。就像我的示例一样,编写非空状态,然后将剩余的记录插入state = null或hive_default_partition中,其方式仍然可以在整个群集中并行进行。
答案 0 :(得分:0)
尝试使用自动分区写入非空数据,然后对空数据重新分区并分别写入,例如:
df.where($”state”.isNotNull).write.partitionBy($”state”).parquet(“my_output_dir”)
df.where($”state”.isNull).repartition(100).write.parquet(“my_output_dir/state=__HIVE_DEFAULT_PARTITION__”)
使用SQL API,您可以使用重新分区提示(Spark 2.4中引入)来完成相同操作:
spark-sql> describe skew_test;
id bigint NULL
dt date NULL
state string NULL
# Partition Information
# col_name data_type comment
state string NULL
Time taken: 0.035 seconds, Fetched 6 row(s)
spark-sql> CREATE TABLE `skew_test2` (`id` BIGINT, `dt` DATE, `state` STRING)
> USING parquet
> OPTIONS (
> `serialization.format` '1'
> )
> PARTITIONED BY (state);
Time taken: 0.06 seconds
spark-sql> insert into table skew_test2 select * from skew_test where state is not null;
Time taken: 1.208 seconds
spark-sql> insert into table skew_test2 select /*+ REPARTITION(100) */ * from skew_test where state is null;
Time taken: 1.39 seconds
您应该看到Spark为最终声明创建了100个任务,并且您的state=__HIVE_DEFAULT_PARTITION__
目录应该包含100个实木复合地板文件。有关Spark-SQL提示的更多信息,请查看https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-hint-framework.html#specifying-query-hints