2017-07-27 64 views
1

我有一個UDF說傳遞UDF的方法或

val testUDF = udf{s: string=>s.toUpperCase} 

我想在一個單獨的方法來創建這個UDF或可能是別的東西像一個實現類,並通過它,它使用它的另一個類。可能嗎?

說假設我有一個A級

class A(df: DataFrame) { 
    def testMethod(): DataFrame = { 
     val demo=df.select(testUDF(col)) 
    } 
} 

A級應該能夠使用UDF。這可以實現嗎?

+0

是絕對有可能:) –

+0

你問如何從創建UDF方法中的函數?如何爲通用函數創建UDF?如何將其傳遞給testMethod?最終目標是什麼? –

+0

你決定接受答案嗎? –

回答

0

如果我理解正確,你實際上會喜歡某種工廠爲特定類A創建此user-defined-function。 這可以通過使用隱式注入的類型類來實現。

E.g. (我不得不定義UDF和數據幀能夠測試這個)

type UDF = String => String 

case class DataFrame(col: String) { 
    def select(in: String) = s"col:$col, in:$in" 
} 

trait UDFFactory[A] { 
    def testUDF: UDF 
} 
implicit object UDFFactoryA extends UDFFactory[AClass] { 
    def testUDF: UDF = _.toUpperCase 
} 

class AClass(df: DataFrame) { 
    def testMethod(implicit factory: UDFFactory[AClass]) = { 
    val demo = df.select(factory.testUDF(df.col)) 
    println(demo) 
    } 
} 

val a = new AClass(DataFrame("test")) 
a.testMethod // prints 'col:test, in:TEST' 
+0

有沒有一種方法可以將UDF傳遞給一個類..例如在你的例子中,AClass將有兩個參數Aclass(df,UDF) – KishoreKumar

+0

@KishoreKumar yes,'class Aclass(df:DataFrame,myUDF:UserDefinedFunction) – puhlen

0

像你所說,創建一個方法完全一樣在你的對象身上或同伴類你的UDF,

val myUDF = udf((str:String) => { str.toUpperCase }) 

那麼對於一些數據框中df爲此,

val res=df withColumn("NEWCOLNAME", myUDF(col("OLDCOLNAME"))) 

這將改變這樣的事情,

+-------------------+ 
|  OLDCOLNAME | 
+-------------------+ 
|  abc  | 
+-------------------+ 

+-------------------+-------------------+ 
|  OLDCOLNAME |  NEWCOLNAME | 
+-------------------+-------------------+ 
|  abc  |  ABC  | 
+-------------------+-------------------+ 

讓我知道,如果這有助於,乾杯。

+0

myUDF缺少udf方法調用(和類型修飾符)。你定義了一個正常的功能... –

+0

雅我有地圖記住,當我寫的。我編輯了我的答案 –

0

給出一個dataframe作爲

+----+ 
|col1| 
+----+ 
|abc | 
|dBf | 
|Aec | 
+----+ 

並有udf功能

import org.apache.spark.sql.functions._ 
val testUDF = udf{s: String=>s.toUpperCase} 

你絕對可以使用另一個類udf功能

val demo = df.select(testUDF(col("col1")).as("upperCasedCol")) 

這應該給你

+-------------+ 
|upperCasedCol| 
+-------------+ 
|ABC   | 
|DBF   | 
|AEC   | 
+-------------+ 

但我建議如果可能的話您使用other functions作爲UDF功能需要被序列化和反序列化列這將耗費時間和內存比其他可用的功能更多。 UDF功能應該是最後的選擇

您可以使用upper function爲你的情況

val demo = df.select(upper(col("col1")).as("upperCasedCol")) 

,這將產生相同的輸出作爲原始udf功能

我希望答案是有幫助的

更新

因爲你的問題是要求提供信息關於如何調用另一個類或對象定義的UDF功能,這裏是法

假設你有,你所定義的UDF函數或者說,我建議作爲

import org.apache.spark.sql.Column 
import org.apache.spark.sql.functions._ 

object UDFs { 

    def testUDF = udf{s: String=>s.toUpperCase} 

    def testUpper(column: Column) = upper(column) 
} 

您的A類函數的對象是你的問題,我只是增加了一個功能

import org.apache.spark.sql.DataFrame 
import org.apache.spark.sql.functions._ 

class A(df: DataFrame) { 
    def testMethod(): DataFrame = { 
    val demo = df.select(UDFs.testUDF(col("col1"))) 
    demo 
    } 

    def usingUpper() = { 
    df.select(UDFs.testUpper(col("col1"))) 
    } 
} 

然後就可以調用從主要功能如下

import org.apache.spark.sql.SparkSession 

object TestUpper { 

    def main(args: Array[String]): Unit = { 
    val sparkSession = SparkSession.builder().appName("Simple Application") 
     .master("local") 
     .config("", "") 
     .getOrCreate() 
    import sparkSession.implicits._ 

    val df = Seq(
     ("abc"), 
     ("dBf"), 
     ("Aec") 
    ).toDF("col1") 

    val a = new A(df) 
    //calling udf function 
    a.testMethod().show(false) 

    //calling upper function 
    a.usingUpper().show(false) 
    } 
} 

我想這是多有幫助

+0

不是有幫助嗎? –

0

是多數民衆贊成儘可能功能Scala的對象可通過周圍:

import org.apache.spark.sql.expressions.UserDefinedFunction 

class A(df: DataFrame, testUdf:UserDefinedFunction) {  
    def testMethod(): DataFrame = { 
     df.select(testUdf(col)) 
    } 
}