根据条件拆分Spark DataFrame

时间:2017-01-31 14:27:53

标签: scala apache-spark dataframe apache-spark-sql

我需要类似于randomSplit函数的东西:

val Array(df1, df2) = myDataFrame.randomSplit(Array(0.6, 0.4))

但是,我需要根据布尔条件拆分myDataFrame。是否存在以下任何内容?

val Array(df1, df2) = myDataFrame.booleanSplit(col("myColumn") > 100)

我不想做两个单独的.filter调用。

2 个答案:

答案 0 :(得分:5)

不幸的是,DataFrame API没有这样的方法,要按照您必须执行两个单独filter转换的条件进行拆分:

myDataFrame.cache() // recommended to prevent repeating the calculation

val condition = col("myColumn") > 100
val df1 = myDataFrame.filter(condition)
val df2 = myDataFrame.filter(not(condition))

答案 1 :(得分:1)

我了解到两次缓存和过滤看起来有些丑陋,但是请记住,DataFrames被转换为RDD,它们是惰性计算的,即仅当它们直接或间接用于操作中时才可以计算。

如果存在问题中建议的方法booleanSplit,则结果将转换为两个RDD,每个RDD都会被懒惰地求值。严格在第一个RDD之后,将首先评估两个RDD中的一个,然后对另一个RDD进行评估。在评估第一个RDD时,第二个RDD尚未“出现”(编辑:刚刚注意到,对于带有answer that gives a similar reasoning的RDD API,存在类似的问题)

要真正获得任何性能上的好处,第二个RDD必须在第一个RDD的迭代过程中(或实际上在两个RDD的父RDD的迭代过程中)被(部分)保留,这是由第一个RDD)。 IMO认为这与RDD API其余部分的设计不太吻合。不确定性能的提高是否可以证明这一点。

我认为您可以实现的最好办法是,通过使用方法booleanSplit编写implicit class来避免在业务代码中直接编写两个过滤器调用,因为实用程序方法以类似的方式来完成该部分像Tzach Zohar's answer一样,也许使用类似于myDataFrame.withColumn("__condition_value", condition).cache()的东西,这样就不会两次计算条件的值。