Spark Dataframes有一个方法withColumn
,一次添加一个新列。要添加多个列,需要withColumn
个链。这是最好的做法吗?
我觉得使用mapPartitions
有更多优点。我们假设我有三个withColumn
s链,然后根据某些条件删除Row
个过滤器。这是四种不同的操作(我不确定这些操作中是否有任何广泛的转换)。但如果我做mapPartitions
,我可以一气呵成。如果我有一个数据库连接,我也希望每个RDD分区打开一次。
我的问题分为两部分。
第一部分,这是我对mapPartitions的实现。这种方法有任何不可预见的问题吗?还有更优雅的方法吗?
df2 = df.rdd.mapPartitions(add_new_cols).toDF()
def add_new_cols(rows):
db = open_db_connection()
new_rows = []
new_row_1 = Row("existing_col_1", "existing_col_2", "new_col_1", "new_col_2")
i = 0
for each_row in rows:
i += 1
# conditionally omit rows
if i % 3 == 0:
continue
db_result = db.get_some_result(each_row.existing_col_2)
new_col_1 = ''.join([db_result, "_NEW"])
new_col_2 = db_result
new_f_row = new_row_1(each_row.existing_col_1, each_row.existing_col_2, new_col_1, new_col_2)
new_rows.append(new_f_row)
db.close()
return iter(new_rows)
第二部分,在mapPartitions
和withColumn
链上使用filter
的权衡是什么?
我在某处读过,使用Spark DFs的可用方法总是比推出自己的实现更好。如果我的论点是错误的,请告诉我。谢谢!欢迎所有的想法。
答案 0 :(得分:4)
这种方法有任何不可预见的问题吗?
多个。最严重的影响是:
DataFrame
代码和显着的垃圾收集开销相比,内存占用量增加了几倍。toDF
调用的模式推断成本(如果提供了正确的模式,则可以避免)以及可能重新执行所有前面的步骤。 udf
和select
/ withColumn
可以避免其中一些,其他则不能。
假设我有一个带有三个withColumns的链,然后有一个过滤器可以根据某些条件删除Rows。这是四种不同的操作(我不确定这些操作中是否有任何广泛的转换)。但如果我做mapPartitions
,我可以一气呵成
您的mapPartitions
不会删除Spark计划程序无法排除的任何操作,也不会提供任何优化。它唯一的优点是它为昂贵的连接对象提供了一个很好的范围。
我在某处读到使用Spark DFs的可用方法总是比推出自己的实现更好
当您开始使用执行程序端Python逻辑时,您已经脱离了Spark SQL。如果您使用udf
,RDD
或新添加的矢量化udf,则无关紧要。在一天结束时,您应该根据代码的整体结构做出决定 - 如果主要是直接在数据上执行的Python逻辑,最好坚持使用RDD
或完全跳过Spark。
如果它只是逻辑的一小部分,并且不会导致严重的性能问题,请不要为此烦恼。
答案 1 :(得分:-1)
使用df.withColumn()
是添加列的最佳方式。他们都懒得加入