【问题标题】:spark: scala - regex as argument for udfspark: scala - 正则表达式作为 udf 的参数
【发布时间】:2019-04-04 22:15:45
【问题描述】:

我正在尝试使用 udf 和代表实际正则表达式的附加参数来检查 scala 数据帧的列与正则表达式。 但是,似乎不允许将正则表达式放入lit() 语句中引发以下错误

java.lang.RuntimeException:不支持的文字类型类 scala.util.matching.Regex

使用下面的示例代码。我希望有一个带有布尔条目的附加列“DMY”。

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._
import scala.util.matching._


def dateDMY_regex(): Regex = """^[0-3]?[0-9][-/.][0-1]?[0-9][-/.](19|20)?\d{2}$""".r

def date_match(value: String, dateEx: Regex): Boolean = {
  return dateEx.unapplySeq(value).isDefined
}

val spark = SparkSession.builder().getOrCreate()

var df = spark.createDataFrame(Seq(
  (0, "31/10/2018"),
  (1, "01/11/2018"),
  (2, "02/11/2018"))).toDF("Id", "col_1")

// to test the function
// print(date_match("31/10/2018", dateDMY_regex()))

val date_match_udf = udf(date_match _)   //, lit("c")
df = df.withColumn( "DMY", date_match_udf( $"col_1", lit(dateDMY_regex()) ) )

df.show()

【问题讨论】:

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


【解决方案1】:

您可以通过 UDF 中的柯里化来提供非列参数(即 dateEx 的值),如下所示:

import org.apache.spark.sql.functions._
import scala.util.matching._

val df = spark.createDataFrame(Seq(
  (0, "31/10/2018"),
  (1, "999/11/2018"),
  (2, "02/11/2018"))
).toDF("Id", "col_1")

val dateEx = """^[0-3]?[0-9][-/.][0-1]?[0-9][-/.](19|20)?\d{2}$""".r

def date_match_udf(dateEx: Regex) = udf(
  (value: String) => dateEx.unapplySeq(value).isDefined
)

df.withColumn("DMY", date_match_udf(dateEx)($"col_1")).
  show
// +---+-----------+-----+
// | Id|      col_1|  DMY|
// +---+-----------+-----+
// |  0| 31/10/2018| true|
// |  1|999/11/2018|false|
// |  2| 02/11/2018| true|
// +---+-----------+-----+

但是,对于您的需要,我建议您使用 Spark 的内置函数,而不是 UDF,这些函数通常性能更好。以下是使用regexp_extract 的一种方法:

val dateExStr = """^([0-3]?[0-9][-/.][0-1]?[0-9][-/.](19|20)?\d{2})$"""

df.withColumn("DMY", $"col_1" === regexp_extract($"col_1", dateExStr, 1)).
  show

【讨论】:

    【解决方案2】:

    我仍然没有实现通过正则表达式。我现在的工作是通过一个字符串并在函数内进行编译。如下:

    import org.apache.spark.sql.SparkSession
    import org.apache.spark.sql.functions._
    import scala.util.matching._
    
    
    def dateDMY_regex(): String = """^[0-3]?[0-9][-/.][0-1]?[0-9][-/.](19|20)?\d{2}$"""
    
    def date_match(value: String, dateEx: String): Boolean = {
      return dateEx.r.unapplySeq(value).isDefined
    }
    
    val spark = SparkSession.builder().getOrCreate()
    
    var df = spark.createDataFrame(Seq(
      (0, "31/10/2018"),
      (1, "01/11/2018"),
      (2, "02/11/2018"))).toDF("Id", "col_1")
    
    // to test the function
    // print(date_match("31/10/2018", dateDMY_regex()))
    
    val date_match_udf = udf(date_match _)   //, lit("c")
    df = df.withColumn( "DMY", date_match_udf( $"col_1", lit(dateDMY_regex()) ) )
    
    df.show()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-22
      • 1970-01-01
      • 2017-05-23
      • 2015-06-19
      • 1970-01-01
      • 2018-07-16
      • 2013-09-19
      • 2013-03-28
      相关资源
      最近更新 更多