Pyspark的懒惰评估循环太慢

时间:2019-01-22 09:24:37

标签: python loops pyspark lazy-evaluation

首先,我想让您知道我仍然很陌生,并且已经习惯了惰性评估概念。

这是我的问题:

我有两个通过读取CSV.GZ文件加载的spark数据帧。 我想做的是合并两个表,以便根据我在第二个表上拥有的键来拆分第一个表。

例如:

表A

+----------+---------+--------+---------+------+
|      Date|     Zone|       X|     Type|Volume|
+----------+---------+--------+---------+------+
|2019-01-16|010010000|       B|        A|   684|
|2019-01-16|010020000|       B|        A| 21771|
|2019-01-16|010030000|       B|        A|  7497|
|2019-01-16|010040000|       B|        A| 74852|

表B

+----+---------+
|Dept|     Zone|
+----+---------+
|  01|010010000|
|  02|010020000|
|  01|010030000|
|  02|010040000|

然后,当我合并两个表时,

+---------+----------+--------+---------+------+----+
|     Zone|      Date|       X|     Type|Volume|Dept|
+---------+----------+--------+---------+------+----+
|010010000|2019-01-16|       B|        A|   684|  01|
|010020000|2019-01-16|       B|        A| 21771|  02|
|010030000|2019-01-16|       B|        A|  7497|  01|
|010040000|2019-01-16|       B|        A| 74852|  02|

所以我要做的是将此表拆分为Y个脱节表,其中Y是我在合并表中找到的不同“ Dept”值的数量。

例如:

结果1:

+---------+----------+--------+---------+------+----+
|     Zone|      Date|       X|     Type|Volume|Dept|
+---------+----------+--------+---------+------+----+
|010010000|2019-01-16|       B|        A|   684|  01|
|010030000|2019-01-16|       B|        A|  7497|  01|

结果2:

+---------+----------+--------+---------+------+----+
|     Zone|      Date|       X|     Type|Volume|Dept|
+---------+----------+--------+---------+------+----+
|010020000|2019-01-16|       B|        A| 21771|  02|
|010040000|2019-01-16|       B|        A| 74852|  02|

我的代码如下:

sp_df_A = spark.read.csv(file_path_A, header=True, sep=';', encoding='cp1252')
sp_df_B = spark.read.csv(file_path_B, header=True, sep=';', encoding='cp1252')

sp_merged_df = sp_df_A.join(sp_df_B, on=['Zone'], how='left')


# list of unique 'Dept' values on the merged DataFrame
unique_buckets = [x.__getitem__('Dept') for x in sp_merged_df.select('Dept').distinct().collect()]


# Iterate over all 'Dept' found
for zone_bucket in unique_buckets:
    print(zone_bucket)
    bucket_dir = os.path.join(output_dir, 'Zone_%s' % zone_bucket)
    if not os.path.exists(bucket_dir):
        os.mkdir(bucket_dir)
    # Filter target 'Dept'
    tmp_df = sp_merged_df.filter(sp_merged_df['Dept'] == zone_bucket)
    # write result
    tmp_df.write.format('com.databricks.spark.csv').option('codec', 'org.apache.hadoop.io.compress.GzipCodec').save(bucket_dir, header = 'true')

问题是,这个非常简单的代码花费太多时间来编写结果。因此,我的猜测是,惰性评估是在循环的每个循环上进行加载,合并和过滤。

会是这种情况吗?

1 个答案:

答案 0 :(得分:1)

您的猜测是正确的。您的代码读取,合并和过滤每个存储桶的所有数据。这确实是由对火花的懒惰评估引起的。

Spark等待任何数据转换,直到执行操作为止。调用动作时,spark会查看所有转换并针对如何有效获取动作结果制定计划。当spark执行此计划时,程序将保持。火花完成后,程序将继续执行,并在执行下一个动作之前将其所做的所有操作“遗忘”。

在您的情况下,spark会“忘记”加入的数据帧sp_merged_df,并且每次调用.collect().save()时,它都会对其进行重构。

如果您想让Spark“记住” RDD或DataFrame,则可以.cache()(请参见docs)。