Scala Explode函数增加了Spark数据帧中的作业时间
我有一个数据帧,其中一列arr的数组大小接近100000。 现在我需要分解此列,以获得数组中所有元素的唯一行 spark.sql的Explode函数正在执行此任务,但需要足够的时间 任何爆炸的选择,我可以尝试优化工作Scala Explode函数增加了Spark数据帧中的作业时间,scala,dataframe,apache-spark,dataset,Scala,Dataframe,Apache Spark,Dataset,我有一个数据帧,其中一列arr的数组大小接近100000。 现在我需要分解此列,以获得数组中所有元素的唯一行 spark.sql的Explode函数正在执行此任务,但需要足够的时间 任何爆炸的选择,我可以尝试优化工作 dfs.printSchema() println("Orginal DF") dfs.show() //Performing Explode operation import org.apache.spark.sql.functions.{explode,col}
dfs.printSchema()
println("Orginal DF")
dfs.show()
//Performing Explode operation
import org.apache.spark.sql.functions.{explode,col}
val opdfs=dfs.withColumn("explarrs",explode(col("arrs"))).drop("arrs")
println("Exploded DF")
opdfs.show()
预期结果应如下所示,但这是该代码的替代方案,可更有效地优化作业
原始DF
+----+------+----+--------------------+
|col1| col2|col3| arrs|
+----+------+----+--------------------+
| A|DFtest| K|[1, 2, 3, 4, 5, 6...|
+----+------+----+--------------------+
Exploded DF
+----+------+----+--------+
|col1| col2|col3|explarrs|
+----+------+----+--------+
| A|DFtest| K| 1|
| A|DFtest| K| 2|
| A|DFtest| K| 3|
| A|DFtest| K| 4|
| A|DFtest| K| 5|
| A|DFtest| K| 6|
| A|DFtest| K| 7|
| A|DFtest| K| 8|
| A|DFtest| K| 9|
| A|DFtest| K| 10|
| A|DFtest| K| 11|
| A|DFtest| K| 12|
| A|DFtest| K| 13|
| A|DFtest| K| 14|
| A|DFtest| K| 15|
| A|DFtest| K| 16|
| A|DFtest| K| 17|
| A|DFtest| K| 18|
| A|DFtest| K| 19|
| A|DFtest| K| 20|
+----+------+----+--------+
only showing top 20 rows
您可以使用Dataframe中的flatMap方法执行相同的操作,而无需进行分解。例如,如果需要分解整数数组,可以执行以下操作:
val els = Seq(Row(Array(1, 2, 3)))
val df = spark.createDataFrame(spark.sparkContext.parallelize(els), StructType(Seq(StructField("data", ArrayType(IntegerType), false))))
df.show()
val els = Seq(Row(Array(1, 2, 3), "data1", "data2"), Row(Array(1, 2, 3, 4, 5, 6), "data10", "data20"))
val df = spark.createDataFrame(spark.sparkContext.parallelize(els),
StructType(Seq(StructField("data", ArrayType(IntegerType), false), StructField("data1", StringType, false), StructField("data2", StringType, false))))
df.show()
df.flatMap{ row =>
val arr = row.getAs[mutable.WrappedArray[Int]](0)
arr.map { el =>
(row.getAs[String](1), row.getAs[String](2), el)
}
}.show()
它给出:
+---------+
| data|
+---------+
|[1, 2, 3]|
+---------+
+------+------+---+
| _1| _2| _3|
+------+------+---+
| data1| data2| 1|
| data1| data2| 2|
| data1| data2| 3|
|data10|data20| 1|
|data10|data20| 2|
|data10|data20| 3|
|data10|data20| 4|
|data10|data20| 5|
|data10|data20| 6|
+------+------+---+
使用Dataframe的平面图:
df.flatMap(row => row.getAs[mutable.WrappedArray[Int]](0)).show()
+-----+
|value|
+-----+
| 1|
| 2|
| 3|
+-----+
问题在于,除了内存开销之外,还需要在getAs函数中放置正确类型的数组元素。正如我在评论中所说,有一个bug已经修复:
但是如果你不能升级你的Spark版本,你可以尝试上面的代码并进行比较
如果要将其他字段添加到结果中,可以执行以下操作:
val els = Seq(Row(Array(1, 2, 3)))
val df = spark.createDataFrame(spark.sparkContext.parallelize(els), StructType(Seq(StructField("data", ArrayType(IntegerType), false))))
df.show()
val els = Seq(Row(Array(1, 2, 3), "data1", "data2"), Row(Array(1, 2, 3, 4, 5, 6), "data10", "data20"))
val df = spark.createDataFrame(spark.sparkContext.parallelize(els),
StructType(Seq(StructField("data", ArrayType(IntegerType), false), StructField("data1", StringType, false), StructField("data2", StringType, false))))
df.show()
df.flatMap{ row =>
val arr = row.getAs[mutable.WrappedArray[Int]](0)
arr.map { el =>
(row.getAs[String](1), row.getAs[String](2), el)
}
}.show()
它给出:
+---------+
| data|
+---------+
|[1, 2, 3]|
+---------+
+------+------+---+
| _1| _2| _3|
+------+------+---+
| data1| data2| 1|
| data1| data2| 2|
| data1| data2| 3|
|data10|data20| 1|
|data10|data20| 2|
|data10|data20| 3|
|data10|data20| 4|
|data10|data20| 5|
|data10|data20| 6|
+------+------+---+
也许会有帮助。您使用的是哪种版本的Spark?。这是在2.3中修复的,我使用的是Spark 2.1.1,如果我的数据框架中有多个列,如下所示+------+---------+----+----+----col1 | col2 | col3 | arrs |+----+----A | DFtest | K |[1,2,3,4]|++------++--------编辑您的问题并添加一些内容,以便更好地理解。嗨,EmiCareOfCell44--感谢您的回复,我编辑了问题并格式化了内容,以便更好地理解上述三列解决方案正在做我的工作。但是与分解方法相比,它需要更多的时间。这取决于有多少列你的记录。由于explode版本在2.3之前的版本中具有指数级的时间复杂度,如果您的记录数增加,您可以使用具有线性增量的flatMap版本进行实验。