将UDF传递给方法或类

时间:2017-07-27 06:34:09

标签: scala apache-spark user-defined-functions

我有一个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。这可以实现吗?

4 个答案:

答案 0 :(得分:0)

如果我理解正确,你会真的想要某种工厂为特定的A类创建这个user-defined-function。 这可以使用隐式注入的类类来实现。

E.g。 (我必须定义UDF和DataFrame以便能够测试它)

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'

答案 1 :(得分:0)

就像你提到的那样,在对象体或伴侣类中创建一个与UDF完全相同的方法,

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

然后对于某些数据帧df执行此操作,

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

这会改变这样的事情,

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

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

让我知道这是否有帮助,干杯。

答案 2 :(得分: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")))
  }
}

然后你可以从main调用函数,如下所示

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)
  }
}

我想这不仅仅是有用的

答案 3 :(得分:0)

是的,因为函数是scala中可以传递的对象:

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

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