2017-07-27 52 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)) 
    } 
}