[英]java.lang.ClassCastException: org.apache.spark.sql.Column cannot be cast to scala.collection.Seq
[英]How to apply UDF to collected Rows? (fails with “java.lang.ClassCastException: java.lang.String cannot be cast to org.apache.spark.sql.Column”)
我有两个数据框,一个包含这样的数据
第一个数据框是这样的
+-----+-----------+-----+----------------------+
|value|mergeValues|table|columnName |
+-----+-----------+-----+----------------------+
|1 |1,2,3 | |columnName1 |
|2 |4,5,6,7 | |columnName1 |
|3 |8,9 | |columnName1 |
|1 |1,2,3 | |columnName4 |
|2 |4,5,6,7 | |columnName4 |
|3 |8,9 | |columnName4 |
|1 |1,2,3 | |columnName5 |
|2 |4,5,6,7 | |columnName5 |
|3 |8,9 | |columnName5 |
|1 |1,2,3 | |columnName6 |
+-----+-----------+-----+----------------------+
另一个数据框结构如下所示
columnName1 | columnName2 | columnName3 |columnName4 |columnName5 | columnName6
1
3
2
4
5
现在,我必须像这样创建映射的数据框。
Mapping logic is : get value from 2ndDF and check firstdf mergeValue if that contains then map to firstdf value. here value of 2nd df columnName1 is 1 it is present in firstDf mergeValues list map it to firstDf[value] which is 1. same for 2,3,4,5,6,7 ...
columnName1 | columnName2 | columnName3 |columnName4 |columnName5 | columnName6
1
1
1
2
2
为此,我使用UDF方式,但是失败了,创建此数据框的正确方法是什么。
我的代码是:
val firstDF=sparkSession.read.load(first)
val testDF = sparkSession.read.load(test)
val populateColumn: ((String, String, String) => String) = (mergeValues: String, value: String,
actualValue: String) => {
if (mergeValues.contains(actualValue.trim)) {
value
} else {
actualValue
}
}
val populateColumnUdf = udf(populateColumn)
val firstDFList=firstDF.collect
firstDFList.foreach(Case => {
println(Case)
testDF.withColumn(Case.getAs("columnName"), populateColumnUdf(Case.getAs("mergeValues"),
Case.getAs("value"), col(Case.getAs("columnName"))))
})
testDF.show
这是我得到的错误
java.lang.String无法转换为org.apache.spark.sql.Column java.lang.ClassCastException:java.lang.String无法转换为org.apache.spark.sql.Column
检查执行以下操作的部分中的类型:
populateColumnUdf(Case.getAs("mergeValues"), Case.getAs("value"), col(Case.getAs("columnName")))
Case
的类型为Row
, getAs
为您提供给定fieldName的值。 (请参阅org.apache.spark.sql.Row )。 那绝对不是您的populateColumnUdf
期望的Column
。 在这种情况下,您宁愿使用populateColumn
Scala函数。 您已经离开了DataFrame / UDF上下文,并且仅在Scala中。
正如Jacek Laskowski所说,在您的代码中, Case是org.apache.spark.sql.Row类型
在Row上调用getAs返回该行在特定字段处的值(例如,第一个数据帧中第一行的值在“ mergeValues”列为“ 1,2,3”)
withColumn方法需要两个参数。 第一个参数是要替换的列的名称,第二个参数是作为替换列的org.apache.spark.sql.Column 。
在第二个参数中,是您提供udf的位置。 udf将列作为参数。 这些输入列的数据类型应对应于udf环绕的函数(在本例中为populateColumn )所期望的输入类型。
不确定您的col()函数在代码中提供给udf的参数内做什么。
如果我正确理解您的代码,那么您将寻找类似以下的内容(此代码不完整,无法运行):
val firstDF = sparkSession.read.load(first)
val testDF = sparkSession.read.load(test)
val populateColumn: ((String, String, String) => String) =
(mergeValues: String, value: String, actualValue: String) => {
if (mergeValues.contains(actualValue.trim)) {
value
} else {
actualValue
}
}
val populateColumnUdf = udf(populateColumn)
val replacementCol = new Column("columnName1")
//mergeValuesCol and valueCol needs to be the columns from firstDF
testDF.withColumn("columnName1", populateColumnUdf(mergeValuesCol, valueCol, replacementCol))
需要提供从firstDF的外部列(mergeValues和值)的值(参见withColumn下传递数据帧列和外部列表到UDF用于参考)。
或者也许考虑在给定条件的情况下合并/合并两个数据框。
希望这会有所帮助! 谢谢编辑问题的人,这样我才能理解问题在问:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.