代码之家  ›  专栏  ›  技术社区  ›  Arjun

如何处理下面的UDF中的空指针异常错误

  •  1
  • Arjun  · 技术社区  · 7 年前

    我正在试着运行UDF udfTest 在下面的df上,但是它碰到了 空指针异常可能是由于date1列中有空值。下面的代码需要做什么更改来处理这个异常?

     +-----------+----------------+----------+
        |info       |date1           | date2    |
        +-----------+----------------+----------+
        |      11111|      2018-04-13|2018-05-20|
        |      11111|                |2018-05-20|
        |      22222|      2018-05-01|2018-05-18|
        |      22222|                |2018-05-20|
        |      33333|      2020-05-03|2018-05-18|
        |      33333|                |2017-04-17|
        |      12931|      2018-05-07|2018-05-07|
        |      12931|      2018-05-03|2018-05-04|
        |      12931|      2018-05-20|2018-05-26|
        |      12931|      2008-05-03|2018-05-20|
        +-----------+----------------+----------+
    
    def get_value(info: String, date1: String, date2: String): String = {
        var str1: String = null
        if (info == "11111" && date1 != null) {
          str1 = date1
        } else if (info == "22222" && date1 != null) {
          str1 = date1
        } else if (info == "33333" && date2 != null) {
          str1 = date2
        } else
          str1 = null
        str1
      }
    
    
      val udfTest = udf((id: String, date1: String, date2: String) => {
        get_value(id: String, date1: String, date2: String)
      })
      df.withColumn("date3", udfTest(df("info"),df("date1"), df("date2")))
    

    错误:

    Caused by: java.lang.NullPointerException
      at java.lang.String.<init>(String.java:152)
      at get_value(<console>:61)
    
    4 回复  |  直到 7 年前
        1
  •  4
  •   rmathews7    7 年前

    您可以考虑使用选项来封装空值。scala代码中乱丢的空值通常被认为是代码味道。也许,这种效果会有所帮助。

    val getValue: (String, String, String) => Option[String] = { (info, date1, date2) =>
      (info, Option(date1), Option(date2)) match {
        case ("11111", Some(d1), _) => Some(d1)
        case ("22222", Some(d1), _) => Some(d1)
        case ("33333", _, Some(d2)) => Some(d2)
        case _ => None
      }
    }
    

    然后您可以在UDF中使用它,如下所示:

    val udfTest = udf(getValue)
    df.withColumn("optional", udfTest(df("info"), df("date1"), df("date2"))).show()
    

    请注意,现在您的数据框中有一个选项[string]列,而不是字符串列。

    Here's scala中可选数据类型的有趣指南,以及有趣的用例。

    编辑:

    这样可以解决有关翻译Holiday Spark SQL代码的问题

    private val yyyyMMddFormat = new SimpleDateFormat("yyyy-MM-dd")
    private val days = List("Saturday", "Sunday")
    private val holidays = List(
      getPreviousDay("2018-05-22"), 
      getPreviousDay("2018-06-01")
    )
    
    def isPreviousDayAHoliday(date: String, days: List[String], holidays: List[java.sql.Date]): Boolean = {
      val previousDay = getPreviousDay(date)
      val eeeeFormat = new SimpleDateFormat("EEEE")
      val dayOfPreviousDay = eeeeFormat.format(previousDay)
      days.contains(dayOfPreviousDay) || holidays.contains(previousDay)
    }
    
    def getPreviousDay(date: String): java.sql.Date = {
      new java.sql.Date(yyyyMMddFormat.parse(date).getTime - DAYS.toMillis(1))
    }
    

    现在你可以用这个当警卫了。

    (info, Option(date1), Option(date2)) match {
      case ("12391", _, Some(d2)) if isPreviousDayAHoliday(d2, days, holidays) => Some(yyyyMMddFormat.format(getPreviousDay(d2)))
      case _ => None
    }
    

    希望这有帮助

        2
  •  2
  •   Ramesh Maharjan    7 年前

    像往常一样,我总是建议 别跟我走 udf 功能 当有内置函数的可选方案时 . AS UDF 函数要求对每一行进行序列化和反序列化,其效率不如内置函数。

    你可以通过使用 when/otherwise , isnull not 内置功能为

    import org.apache.spark.sql.functions._
    df.withColumn("date3",
      when(not(isnull(col("date1"))) && col("info") === "11111", col("date1")).otherwise(
      when(not(isnull(col("date1"))) && col("info") === "22222", col("date1")).otherwise(
        when(not(isnull(col("date2"))) && col("info") === "33333", col("date2")).otherwise(lit(null))
      )
      )
    )
    

    或者只是使用 何时/以其他方式 isNotNull 功能

    import org.apache.spark.sql.functions._
    df.withColumn("date3",
      when(col("date1").isNotNull && col("info") === "11111", col("date1")).otherwise(
      when(col("date1").isNotNull && col("info") === "22222", col("date1")).otherwise(
        when(col("date2").isNotNull && col("info") === "33333", col("date2")).otherwise(lit(null))
      )
      )
    )
    
        3
  •  1
  •   senjin.hajrulahovic    7 年前

    为了防止空指针异常,可以将字符串常量与INFO变量进行比较,而不是反过来。您不需要str1变量。与你的建议不同的工作方案至少是:

    def get_value(info: String, date1: String, date2: String): String = {
      if ("11111" == info && date1 != null) {
        date1
      } else if ("22222" == info && date1 != null) {
        date1
      } else if ("33333" == info && date2 != null) {
        date2
      } else
        "null"
    }
    
        4
  •  0
  •   Arjun    7 年前

    使用 Option 成功了。

       def get_value(info: String, date1: String, date2: String): String = {
        var str1: String = null
      if ("11111" == info && date1 != null) {
        Option(tdate1).getOrElse("null")
      } else if ("22222" == info && date1 != null) {
        Option(tdate1).getOrElse("null")
      } else if ("33333" == info && date2 != null) {
        Option(tdate2).getOrElse("null")
      } else
        Option(str1).getOrElse("null")
    }
    
    推荐文章