Scala 如何使用一个列表(1000个条目)高效地生成一个Spark数据帧(100万行)笛卡尔积,从而生成一个包含10亿行的新数据帧
我想获取一个数据帧的每一行,它有100万行,并从每一行生成1000行,方法是获取一个具有1000个条目的列表的叉积,从而生成一个具有10亿行的数据帧。有效地做这件事的最佳方法是什么。Scala 如何使用一个列表(1000个条目)高效地生成一个Spark数据帧(100万行)笛卡尔积,从而生成一个包含10亿行的新数据帧,scala,apache-spark,dataframe,rdd,Scala,Apache Spark,Dataframe,Rdd,我想获取一个数据帧的每一行,它有100万行,并从每一行生成1000行,方法是获取一个具有1000个条目的列表的叉积,从而生成一个具有10亿行的数据帧。有效地做这件事的最佳方法是什么。 我尝试过广播列表,然后在映射数据帧的每一行时使用它。但这似乎花费了太多时间 val mappedrdd = validationDataFrames.map(x => { val cutoffList : List[String] = cutoffListBroadcast.value
我尝试过广播列表,然后在映射数据帧的每一行时使用它。但这似乎花费了太多时间
val mappedrdd = validationDataFrames.map(x => {
val cutoffList : List[String] = cutoffListBroadcast.value
val arrayTruthTableVal = arrayTruthTableBroadcast.value
var listBufferRow: ListBuffer[Row] = new ListBuffer()
for(cutOff <- cutoffList){
val conversion = x.get(0).asInstanceOf[Int]
val probability = x.get(1).asInstanceOf[Double]
var columnName : StringBuffer = new StringBuffer
columnName = columnName.append(conversion)
if(probability > cutOff.toDouble){
columnName = columnName.append("_").append("1")
}else{
columnName = columnName.append("_").append("0")
}
val index:Int = arrayTruthTableVal.indexOf(columnName.toString)
var listBuffer : ListBuffer[String] = new ListBuffer()
listBuffer :+= cutOff
for(i <- 1 to 4){
if((index + 1) == i) listBuffer :+= "1" else listBuffer :+= "0"
}
val row = Row.fromSeq(listBuffer)
listBufferRow = listBufferRow :+ row
}
listBufferRow
})
val-mappedrdd=validationDataFrames.map(x=>{
val截止列表:列表[字符串]=截止列表广播.value
val arrayTruthTableVal=arrayTruthTableBroadcast.value
var listBufferRow:ListBuffer[Row]=新ListBuffer()
用于(截止。toDouble){
columnName=columnName.append(“”).append(“1”)
}否则{
columnName=columnName.append(“”).append(“0”)
}
val index:Int=arrayTruthTableVal.indexOf(columnName.toString)
var listBuffer:listBuffer[String]=new listBuffer()
listBuffer:+=截止
对于(i根据您的spark版本,您可以执行以下操作:
def time[R](block: => R): Long = {
val t0 = System.currentTimeMillis()
block // call-by-name
val t1 = System.currentTimeMillis()
t1 - t0
}
time(spark.range(1000000).withColumn("a",lit((0 until 1000).toArray)).withColumn("a", explode($"a")).count())
Spark 2.1.0
将列表添加为列并分解。一个简化示例:
val df = spark.range(5)
val exploded = df.withColumn("a",lit(List(1,2,3).toArray)).withColumn("a", explode($"a"))
df.show()
+---+---+
| id| a|
+---+---+
| 0| 1|
| 0| 2|
| 0| 3|
| 1| 1|
| 1| 2|
| 1| 3|
| 2| 1|
| 2| 2|
| 2| 3|
| 3| 1|
| 3| 2|
| 3| 3|
| 4| 1|
| 4| 2|
| 4| 3|
+---+---+
对于计时,您可以执行以下操作:
def time[R](block: => R): Long = {
val t0 = System.currentTimeMillis()
block // call-by-name
val t1 = System.currentTimeMillis()
t1 - t0
}
time(spark.range(1000000).withColumn("a",lit((0 until 1000).toArray)).withColumn("a", explode($"a")).count())
在一台16核计算机上花费了5.41秒,该计算机有大量内存,默认并行度为60
您可以定义一个简单的UDF
val xx = (0 until 1000).toArray.toSeq // replace with your list but turn it to seq
val ff = udf(() => {xx})
time(spark.range(1000000).withColumn("a",ff()).withColumn("a", explode($"a")).count())
在8.25秒以上的同一台服务器上运行您考虑过使用数据集吗?您将从内置优化中获益,您可以对两个表应用交叉连接“但这似乎花费了太多时间。”它需要多长时间,您预计需要多长时间?生成10亿行将是非常昂贵的。实际上它永远不会完成。它会被困在listBufferRow=listBufferRow:+row执行器的线程转储时,我可以看到被困在listBufferRow=listBufferRow:+row的线程在r上也可以正常工作兴高采烈的小DF。