我在我的Scala应用程序中使用spark 2.3。我有一个从spark sql创建的数据框,该数据框在我共享的示例代码中名为sqlDF。我有一个包含以下项目的字符串列表
列表[]字符串列表项
-9,-8,-7,-6
我想将数据框中所有列中与此列表项匹配的所有值替换为0。
初始数据框
column1 | column2 | column3
1 |1 |1
2 |-5 |1
6 |-6 |1
-7 |-8 |-7
它必须返回到
column1 | column2 | column3
1 |1 |1
2 |-5 |1
6 |0 |1
0 |0 |0
为此,我为sqlDF中的所有列(超过500个)设置了以下查询。
sqlDF = sqlDF.withColumn(currColumnName, when(col(currColumnName).isin(stringList:_*), 0).otherwise(col(currColumnName)))
但是,如果我只选择一列进行迭代,则会收到以下错误,但是如果我在上面的代码中进行500列迭代,它将失败
线程“ streaming-job-executor-0”中的异常 java.lang.StackOverflowError在 scala.collection.generic.GenTraversableFactory $ GenericCanBuildFrom.apply(GenTraversableFactory.scala:57) 在 scala.collection.generic.GenTraversableFactory $ GenericCanBuildFrom.apply(GenTraversableFactory.scala:52) 在 scala.collection.TraversableLike $ class.builder $ 1(TraversableLike.scala:229) 在 scala.collection.TraversableLike $ class.map(TraversableLike.scala:233) 在scala.collection.immutable.List.map(List.scala:285)在 org.apache.spark.sql.catalyst.trees.TreeNode $$ anonfun $ 4.apply(TreeNode.scala:333) 在 org.apache.spark.sql.catalyst.trees.TreeNode.mapProductIterator(TreeNode.scala:187)
我想念的是什么?
答案 0 :(得分:2)
这是在left anti join
和columnX
之间应用X
的另一种方法,其中X是传输到数据框中的项目列表。左反连接将返回X
中不存在的所有项目,我们通过外部连接将它们连接在一起的结果(可以将其替换为左连接以获得更好的性能,但这会排除全零的记录,即id == 3)基于分配给monotonically_increasing_id的ID:
import org.apache.spark.sql.functions.{monotonically_increasing_id, col}
val df = Seq(
(1, 1, 1),
(2, -5, 1),
(6, -6, 1),
(-7, -8, -7))
.toDF("c1", "c2", "c3")
.withColumn("id", monotonically_increasing_id())
val exdf = Seq(-9, -8, -7, -6).toDF("x")
df.columns.map{ c =>
df.select("id", c).join(exdf, col(c) === $"x", "left_anti")
}
.reduce((df1, df2) => df1.join(df2, Seq("id"), "outer"))
.na.fill(0)
.show
输出:
+---+---+---+---+
| id| c1| c2| c3|
+---+---+---+---+
| 0| 1| 1| 1|
| 1| 2| -5| 1|
| 3| 0| 0| 0|
| 2| 6| 0| 1|
+---+---+---+---+
答案 1 :(得分:1)
foldLeft
非常适合您的情况,如下所示
val df = spark.sparkContext.parallelize(Seq(
(1, 1, 1),
(2, -5, 1),
(6, -6, 1),
(-7, -8, -7)
)).toDF("a", "b", "c")
val list = Seq(-7, -8, -9)
val resultDF = df.columns.foldLeft(df) { (acc, name) => {
acc.withColumn(name, when(col(name).isin(list: _*), 0).otherwise(col(name)))
}
}
输出:
+---+---+---+
|a |b |c |
+---+---+---+
|1 |1 |1 |
|2 |-5 |1 |
|6 |-6 |1 |
|0 |0 |0 |
+---+---+---+
答案 2 :(得分:0)
我建议您广播String列表:
val stringList=sc.broadcast(<Your List of List[String]>)
在此之后使用此:
sqlDF = sqlDF.withColumn(currColumnName, when(col(currColumnName).isin(stringList.value:_*), 0).otherwise(col(currColumnName)))
确保您的currColumnName也是字符串格式。比较应该是字符串到字符串