我想在写入文件之前根据索引列将Spark DataFrame划分为偶数个分区。我想根据DataFrame的大小来控制要创建多少个分区,然后在使用partitionBy
写入Parquet文件时使用then。
有一个示例DataFrame:
i b
0 11
1 9
2 13
3 2
4 15
5 3
6 14
7 16
8 11
9 9
10 17
11 10
假设我想基于i
列中的值创建4个分区,则这些分区将对应于分配给g
列的值:
g i b
0 0 11
0 1 9
0 2 13
1 3 2
1 4 15
1 5 3
2 6 14
2 7 16
2 8 11
3 9 9
3 10 17
3 11 10
在Spark中执行此操作的首选方式是什么?
答案 0 :(得分:1)
尽管文档似乎有点难以理解,并且对这个问题做出了一些假设-例如,它希望将4个或N个file(?)作为输出,并以递增方式对列为“ i”的id进行声明,因此我自己的 Spark 2.4 改编示例,它获取20条记录并将它们分成4个均匀分布的分区,然后将其写出。我们去吧
val list = sc.makeRDD((1 to 20)).map((_, 1,"2019-01-01", "2019-01-01",1,2,"XXXXXXXXXXXXXXXXXXXXXXXXXX"))
val df = list.toDF("customer_id", "dummy", "report_date", "date", "value_1", "value_2", "dummy_string")
df.show(false)
仅显示一些条目:
+-----------+-----+-----------+----------+-------+-------+--------------------------+
|customer_id|dummy|report_date|date |value_1|value_2|dummy_string |
+-----------+-----+-----------+----------+-------+-------+--------------------------+
|1 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
|2 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
|3 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
|4 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
|5 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
|6 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
|7 |1 |2019-01-01 |2019-01-01|1 |2 |XXXXXXXXXXXXXXXXXXXXXXXXXX|
...
然后-包括一些额外的排序方法-不需要,可以使用所有格式:
df.repartitionByRange(4, $"customer_id")
.sortWithinPartitions("customer_id", "date", "value_1")
.write
.parquet("/tmp/SOQ6")
如下图所示,它提供了4个文件:
您可以看到4个文件,第一部分和最后部分的命名是显而易见的。正在运行:
val lines = spark.read.parquet("/tmp/SOQ6/part-00000-tid-2518447510905190948-a81455f6-6c0b-4e02-89b0-57dfddf1fb97-1200-c000.snappy.parquet")
val words = lines.collect
lines.count
显示5条记录,以及根据数据帧连续排序的内容。
lines: org.apache.spark.sql.DataFrame = [customer_id: int, dummy: int ... 5 more fields]
words: Array[org.apache.spark.sql.Row] = Array([1,1,2019-01-01,2019-01-01,1,2,XXXXXXXXXXXXXXXXXXXXXXXXXX], [2,1,2019-01-01,2019-01-01,1,2,XXXXXXXXXXXXXXXXXXXXXXXXXX], [3,1,2019-01-01,2019-01-01,1,2,XXXXXXXXXXXXXXXXXXXXXXXXXX], [4,1,2019-01-01,2019-01-01,1,2,XXXXXXXXXXXXXXXXXXXXXXXXXX], [5,1,2019-01-01,2019-01-01,1,2,XXXXXXXXXXXXXXXXXXXXXXXXXX])
res11: Long = 5
在所有文件上都使用此选项,但只显示一个。
最终评论
这是一个好主意是一个不同的故事,例如想起非广播的JOIN就是一个问题。
此外,我显然不会对4进行硬编码,而是为N应用一些公式以应用于partitionByRange!例如:
val N = some calculation based on counts in DF and your cluster val df2 = df.repartition(N, $"c1", $"c2")
由于文档尚不完全清楚,您必须测试DF Writer。
在具有2M条记录的EMR群集上进行检查,并且在输出方面也检查了4个文件。