Передача аргументов в udf из столбцов, присутствующих в списке строк

#scala #apache-spark #apache-spark-sql

#scala #apache-spark #apache-spark-sql

Вопрос:

У меня есть список строк, которые представляют имена столбцов внутри фрейма данных. Я хочу передать аргументы из этих столбцов в udf. Как я могу это сделать в spark scala?

    val actualDF = Seq(
             ("beatles", "help|hey jude","sad",4),
             ("romeo", "eres mia","old school",56)
            ).toDF("name", "hit_songs","genre","xyz")


   val column_list: List[String] = List("hit_songs","name","genre")

   // example udf
   val testudf = org.apache.spark.sql.functions.udf((s1: String, s2: String) => {
     // lets say I want to concat all values
   })


   val finalDF = actualDF.withColumn("test_res",testudf(col(column_list(0))))
  

Из приведенного выше примера я хочу передать свой список column_list в udf. Я не уверен, как я могу передать полный список строк, представляющих имена столбцов. Хотя в случае 1 элемента, который я видел, я могу это сделать col(column_list(0))) . Пожалуйста, поддержите.

Ответ №1:

Заменить

 testudf(col(column_list(0)))
  

с

 testudf(column_list: _*)
  

Это интерпретирует список как несколько отдельных входных аргументов.

Комментарии:

1. Это будет работать только для двух значений в column_list , может произойти сбой, если column_list имеет более двух значений.

Ответ №2:

hit_songs имеет тип Seq[String] , на который вам нужно изменить первый параметр вашего udf Seq[String] .

 scala> singersDF.show(false)
 ------- ------------- ---------- 
|name   |hit_songs    |genre     |
 ------- ------------- ---------- 
|beatles|help|hey jude|sad       |
|romeo  |eres mia     |old school|
 ------- ------------- ---------- 
  
 scala> actualDF.show(false)
 ------- ---------------- ---------- 
|name   |hit_songs       |genre     |
 ------- ---------------- ---------- 
|beatles|[help, hey jude]|sad       |
|romeo  |[eres mia]      |old school|
 ------- ---------------- ---------- 
  
 scala> column_list
res27: List[String] = List(hit_songs, name)
  

Измените свой UDF вариант ниже.

 // s1 is of type Seq[String]
val testudf = udf((s1:Seq[String],s2:String) => {
    s1.mkString.concat(s2)
})

  

Применение UDF

 scala> actualDF
.withColumn("test_res",testudf(col(column_list.head),col(column_list.last)))
.show(false)
 ------- ---------------- ---------- ------------------- 
|name   |hit_songs       |genre     |test_res           |
 ------- ---------------- ---------- ------------------- 
|beatles|[help, hey jude]|sad       |helphey judebeatles|
|romeo  |[eres mia]      |old school|eres miaromeo      |
 ------- ---------------- ---------- ------------------- 
  

Без UDF

 scala> actualDF.withColumn("test_res",concat_ws("",$"name",$"hit_songs")).show(false) // Without UDF.
 ------- ---------------- ---------- ------------------- 
|name   |hit_songs       |genre     |test_res           |
 ------- ---------------- ---------- ------------------- 
|beatles|[help, hey jude]|sad       |beatleshelphey jude|
|romeo  |[eres mia]      |old school|romeoeres mia      |
 ------- ---------------- ---------- -------------------