【问题标题】:Creting UDF function with NonPrimitive Data Type and using in Spark-sql Query: Scala创建具有非原始数据类型的 UDF 函数并在 Spark-sql 查询中使用:Scala
【发布时间】:2020-08-22 07:28:00
【问题描述】:

我正在 scala 中创建一个函数,我想在我的 spark-sql 查询中使用它。我的查询在 hive 中运行良好,或者如果我在 spark sql 中给出相同的查询,但我在多个使用相同的查询地方,所以我想将它创建为可重用的函数/方法,所以只要它需要我就可以调用它。 我在我的 scala 类中创建了以下函数。

def date_part(date_column:Column) = {
    val m1: Column = month(to_date(from_unixtime(unix_timestamp(date_column, "dd-MM-yyyy")))) //give  value as 01,02...etc

    m1 match {
        case 01 => concat(concat(year(to_date(from_unixtime(unix_timestamp(date_column, "dd-MM- yyyy"))))-1,'-'),substr(year(to_date(from_unixtime(unix_timestamp(date_column, "dd-MM-yyyy")))),3,4))
        //etc..
        case _ => "some other logic"
    }
}

但它显示多个错误。

  1. 对于 01:

◾十进制整数文字可能没有前导零。 (八进制语法 已经过时了。)

◾类型不匹配;找到:需要 Int(0):org.apache.spark.sql.Column。

  1. 对于“-”:

类型不匹配;发现:需要 Char('-'): org.apache.spark.sql.Column.

  1. 对于“substr”:

未找到:值 substr.

另外,如果我创建的任何简单函数也使用类型作为列,我无法注册它,因为我在列格式中无法获得错误。对于所有原始数据类型(String,Long,Int )它工作正常。但在我的情况下,类型是列所以 我无法做到这一点。有人可以指导我该怎么做。到目前为止,我在 stack-overflow 上发现我需要将此函数与 df 一起使用,然后需要将此 df 转换为临时表。有人可以请指导我任何其他替代方式,以便我现有代码无需太多更改即可使用此功能。

【问题讨论】:

  • 你能告诉我你想要的输入和输出的细节吗??
  • 输入-->date_column--->即03-01-2019 首先我想获取月份部分并分配到 m1 即 01 ..如果月份 01 然后检查 case 语句并希望输出为 012019(mmyyyy) 等..@Srinivas
  • 我在下面添加了答案,请检查并让我知道它是否不起作用..

标签: scala apache-spark hive apache-spark-sql


【解决方案1】:

试试下面的代码。

scala> import org.joda.time.format._
import org.joda.time.format._

scala> spark.udf.register("datePart",(date:String) => DateTimeFormat.forPattern("MM-dd-yyyy").parseDateTime(date).toString(DateTimeFormat.forPattern("MMyyyy")))
res102: org.apache.spark.sql.expressions.UserDefinedFunction = UserDefinedFunction(<function1>,StringType,Some(List(StringType)))

scala> spark.sql("""select datePart("03-01-2019") as datepart""").show
+--------+
|datepart|
+--------+
|  032019|
+--------+

【讨论】:

  • 非常感谢@Srinivas 它对我有用。当我在单独的 scala 对象中编写此代码作为对象 UDF_Class { def MMyyyy_Date(args: Array[String]) = { spark .udf.register("datePart",(date:String) => DateTimeFormat.forPattern("MM-dd-yyyy").parseDateTime(date).toString(DateTimeFormat.forPattern("MMyyyy"))) } } 然后调用另一个类作为 import pkg_name.UDF_Class.MMyyyy_Date 然后在 sparksql 查询中使用它作为 spark.sql("select datePar(columnname) as dpart from dbname.tablename")
  • 它显示的不是注册功能,我需要在我想使用它的第二个课程中添加更多的东西(导入..)。
  • 你必须在你想使用的地方注册 udf 或保存在包对象中并导入该包它将可用。
【解决方案2】:

首先,Spark 需要读取一个存储数据的文件,我猜这个文件是 CSV,但你可以使用方法 json insted of csv。

然后您可以添加具有计算值的新列,如下所示:

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

      val df = spark.read
        .option("header", "true")
        .option("inferSchema", "true")
        .csv("/path/mydata.csv")

      def transformDate( dateColumn: String, df: DataFrame) : DataFrame = {
         df.withColumn("calculatedCol", month(to_date(from_unixtime(unix_timestamp(col(dateColumn), "dd-MM-yyyy")))))

         df.withColumn("newColumnWithDate",  when(col("calculatedCol") === "01", concat(concat(year(to_date(from_unixtime(unix_timestamp(col("calculatedCol"), "dd-MM- yyyy"))))-1, lit('-')),substring(year(to_date(from_unixtime(unix_timestamp(col("calculatedCol")), "dd-MM-yyyy"))),4,2))
          .when(col("calculatedCol") === "02","some other logic")
          .otherwise("nothing match")))
      }

     // calling your function for the Dataframe you want transform date column:
     transformDate("date_column", df)

注意有些函数需要一个列作为参数,而不是字符串值,所以使用 lit() 来指定这些值。

不需要UDF(并且在性能方面不推荐),但您可以通过以下方式使用它:

val upper: String => String = _.toUpperCase
import org.apache.spark.sql.functions.udf
val upperUDF = udf(upper)
df.withColumn("upper", upperUDF('text)).show

“上部”函数将是您必须包含转换日期列的逻辑的方法。

【讨论】:

  • 但在那种情况下它不能重复使用对吗?我需要编写这么多代码的地方我想将它用作可重复使用的函数,所以我可以在任何需要的地方调用它@mrElefant
  • 是的,我将编辑我的答案来描述一个可重用的功能......让我等 5 分钟
  • 就这样吧,够不够用告诉我
  • 非常感谢@MrElephant 和Srinivas 您的回答对我帮助很大。但是在实施MrElephant 提到的第二个UDF 时我仍然面临一些问题。我已经在这里stackoverflow.com/questions/61662077/… 发布了这个问题,因为我不得不粘贴代码并且在评论部分我无法粘贴完整的代码。
猜你喜欢
  • 2019-07-05
  • 2017-09-16
  • 2018-01-01
  • 1970-01-01
  • 2017-09-22
  • 2017-08-04
  • 2016-12-02
  • 2017-02-19
  • 1970-01-01
相关资源
最近更新 更多