我有两个数据框,其中包含这样的数据
第一个数据框就是这样的
+-----+-----------+-----+----------------------+
|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
答案 0 :(得分:1)
检查执行以下操作的部件中的类型:
populateColumnUdf(Case.getAs("mergeValues"), Case.getAs("value"), col(Case.getAs("columnName")))
Case
的类型为Row
,getAs
为您提供给定fieldName的值。(请参阅org.apache.spark.sql.Row)。那个Column
期望的肯定不 populateColumnUdf
。在这种情况下,您宁愿使用populateColumn
Scala函数。您已离开DataFrame / UDF上下文,仅在Scala中。
答案 1 :(得分:1)
正如Jacek Laskowski所说,在你的代码中, Case 是一个org.apache.spark.sql.Row类型
在行上调用 getAs 会在特定字段返回此行的值(例如,第一个数据框中第一行的值为“1, 2,3“在”mergeValues“栏)
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和value)中的值(有关参考,请参阅Passing a data frame column and external list to udf under withColumn)。
或者考虑合并/加入给定条件的两个数据帧。
希望这有点帮助! 感谢编辑问题的人,以便我能理解问题是什么:)