繁体   English   中英

如何将UDF应用于收集的行? (失败与“ java.lang.ClassCastException:java.lang.String无法转换为org.apache.spark.sql.Column”)

[英]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的类型为RowgetAs为您提供给定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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM