Scala 使用带有外部函数的WithColumn

Scala 使用带有外部函数的WithColumn,scala,apache-spark,apache-spark-sql,user-defined-functions,Scala,Apache Spark,Apache Spark Sql,User Defined Functions,我在数据框中有以下列的数据 文件格式为csv 以下所有列数据类型都是字符串 员工ID、pexpense、cexpense 现在我需要创建一个新的DataFrame,它有一个名为expense的新列,该列是根据列pexpense,cexpense计算的 棘手的部分是,计算算法不是我创建的一个UDF函数,而是一个外部函数,需要从Java库中导入,该库将基本类型作为参数—在本例中是pexpense,cexpense—来计算新列所需的值 来自外部Java jar的函数签名 public class My

我在数据框中有以下列的数据

  • 文件格式为csv
  • 以下所有列数据类型都是字符串

    员工ID、pexpense、cexpense

  • 现在我需要创建一个新的DataFrame,它有一个名为
    expense
    的新列,该列是根据列
    pexpense
    cexpense
    计算的

    棘手的部分是,计算算法不是我创建的一个UDF函数,而是一个外部函数,需要从Java库中导入,该库将基本类型作为参数—在本例中是
    pexpense
    cexpense
    —来计算新列所需的值

    来自外部Java jar的函数签名

    public class MyJava
    
    {
    
        public Double calculateExpense(Double pexpense, Double cexpense) {
           // calculation
        }
    
    }
    

    那么我如何调用这个外部函数来创建一个新的计算列呢。我可以在Spark应用程序中将该外部函数注册为UDF吗?

    下面是两列求和的示例:

    val somme= udf((a: Int, b: int) => a+b)
    
    val df_new = df.select(col("employeeid"), \
                           col("pexpense"),   \
                           col("pexpense"),   \
                           somme(col("pexpense"), col("pexpense")) as "expense")
    
    只需将给定方法作为参数传递给
    org.apache.spark.sql.functions
    中的
    UDF
    函数,即可将其“包装”到UDF中:

    import org.apache.spark.sql.functions._
    import spark.implicits._
    
    val myUdf = udf(calculateExpense _)
    val newDF = df.withColumn("expense", myUdf($"pexpense", $"cexpense"))
    

    这假设
    pexpense
    cexpense
    列都是
    Double
    s.

    您可以创建与以下类似的外部方法的自定义项(使用Scala REPL进行说明):


    正如我提到的calculateExpense是一个外部函数,它是名为MyJava的类的一部分。我需要实例化这个类并使用对象引用调用它。您的解决方案仍然有效吗?(离线)-答案是肯定的,您只需实例化一个MyJava实例并使用它引用该方法,正如@leo-c在一个类似的回答中所显示的那样……该函数是一个外部Java函数,不是我在应用程序中定义的UDF。我正要发布同样的内容,但无论如何,感谢您的回答!
    // From a Linux shell prompt:
    
    vi MyJava.java
    public class MyJava {
        public Double calculateExpense(Double pexpense, Double cexpense) {
            return pexpense + cexpense;
        }
    }
    :wq
    
    javac MyJava.java
    jar -cvf MyJava.jar MyJava.class
    
    spark-shell --jars /path/to/jar/MyJava.jar
    
    // From within the Spark shell
    
    val df = Seq(
      ("1", "1.0", "2.0"), ("2", "3.0", "4.0")
    ).toDF("employeeid", "pexpense", "cexpense")
    
    val myJava = new MyJava
    
    val myJavaUdf = udf(
      myJava.calculateExpense _
    )
    
    val df2 = df.withColumn("totalexpense", myJavaUdf($"pexpense", $"cexpense") )
    
    df2.show
    +----------+--------+--------+------------+
    |employeeid|pexpense|cexpense|totalexpense|
    +----------+--------+--------+------------+
    |         1|     1.0|     2.0|         3.0|
    |         2|     3.0|     4.0|         7.0|
    +----------+--------+--------+------------+