簡體   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