我有一个实木复合地板格式的大型数据集(大小约为1TB),分为两个层次结构:CLASS
和DATE
只有7个班级。但是日期从2020-01-01起一直在增加。
我的数据先按CLASS
分区,然后按DATE
类似这样:
CLASS1---DATE 1
---DATE 2
--- .
--- .
--- .
---DATE N
CLASS2---DATE 1
---DATE 2
--- .
--- .
--- .
---DATE N
我通过CLASS
在for循环中加载数据。如果加载整个实木复合地板文件,YARN将杀死该作业,因为它会使内存实例超载。但是自从我在建模中执行百分位计算以来,我一直都在加载。此方法大约需要23个小时才能完成。
但是,如果我重新分区以仅拥有CLASS
分区,则该作业大约需要10个小时。
子分区过多是否会降低Spark executor的工作速度?
我之所以将分区层次结构保持为CLASS
-> DATE
,仅是因为我每天都需要通过DATE
附加新数据。
如果只有1个分区更有效,那么在加载新数据后,我每天都必须重新分区为CLASS
分区。
有人可以解释为什么拥有一个分区能更快地工作吗?如果是这样,那么每天通过追加而不重新分割整个数据集的最佳方法是什么?
谢谢
编辑:
我在文件结构上使用for循环像这样通过CLASS
分区循环:
fs = s3fs.S3FileSystem(anon=False)
inpath="s3://bucket/file.parquet/"
Dirs= fs.ls(inpath)
for paths in Dirs:
customPath='s3://' + uvapath + '/'
class=uvapath.split('=')[1]
df=spark.read.parquet(customPath)
outpath="s3://bucket/Output_" + class + ".parquet"
#Perform calculations
df.write.mode('overwrite').parquet(outpath)
已加载的df
将具有CLASS=1
的所有日期。然后,我为每个CLASS
将文件输出为单独的实木复合地板文件,这样我就有7个实木复合地板文件:
Output_1.parquet
Output_2.parquet
Output_3.parquet
Output_4.parquet
Output_5.parquet
Output_6.parquet
Output_7.parquet
然后我将7个实木复合地板合并为一个实木复合地板不是问题,因为生成的实木复合地板文件要小得多。
答案 0 :(得分:1)
我有包含三列的分区数据,年份,月份和ID。文件夹路径层次结构是
year=2020/month=08/id=1/*.parquet
year=2020/month=08/id=2/*.parquet
year=2020/month=08/id=3/*.parquet
...
year=2020/month=09/id=1/*.parquet
year=2020/month=09/id=2/*.parquet
year=2020/month=09/id=3/*.parquet
我可以通过加载根路径来读取DataFrame。
val df = spark.read.parquet("s3://mybucket/")
然后,已分区的列将自动添加到DataFrame中。现在,您可以通过以下方式过滤分区列的数据
val df_filtered = df.filter("year = '2020' and month = '09'")
并使用df_filtered
进行操作,则火花将仅使用分区的数据!
对于重复处理,可以使用火花的fair scheduler
。使用以下代码,将fair.xml文件添加到项目的src / main / resources中
<?xml version="1.0"?>
<allocations>
<pool name="fair">
<schedulingMode>FAIR</schedulingMode>
<weight>10</weight>
<minShare>0</minShare>
</pool>
</allocations>
并在创建spark会话后设置spark配置。
spark.sparkContext.setLocalProperty("spark.scheduler.mode", "FAIR")
spark.sparkContext.setLocalProperty("spark.scheduler.allocation.file", getClass.getResource("/fair.xml").getPath)
spark.sparkContext.setLocalProperty("spark.scheduler.pool", "fair")
然后,您可以并行完成工作。您可能要根据CLASS并行化作业,所以
val classes = (1 to 7).par
val date = '2020-09-25'
classes foreach { case i =>
val df_filtered = df.filter(s"CLASS == '$i' and DATE = '$date'")
// Do your job
}
代码将在不同的CLASS值下同时工作。