如何在Scala中的Dataframe的String列上应用Regex模式?

时间:2018-08-21 12:09:19

标签: scala apache-spark

我有一个数据框yeadDF,它是通过读取RDBMS表创建的,如下所示:

val yearDF = spark.read.format("jdbc").option("url", connectionUrl)
                                                .option("dbtable", s"(${query}) as year2017")
                                                .option("user", devUserName)
                                                .option("password", devPassword)
                                                .option("numPartitions",15)
                                                .load()

在将其导入HDFS的Hive表之前,我必须对上述数据框应用正则表达式模式。下面是正则表达式模式:

regexp_replace(regexp_replace(regexp_replace(regexp_replace(regexp_replace(%s, E'[\\\\n]+', ' ', 'g' ), E'[\\\\r]+', ' ', 'g' ), E'[\\\\t]+', ' ', 'g' ), E'[\\\\cA]+', ' ', 'g' ), E'[\\\\ca]+', ' ', 'g' )

我应该仅在数据帧yearDF中数据类型为String的列上应用此正则表达式。我尝试了以下方法:

val regExpr = yearDF.schema.fields
    .map(x => 
        if(x.dataType == String)
             "regexp_replace(regexp_replace(regexp_replace(regexp_replace(regexp_replace(%s, E'[\\\\n]+', ' ', 'g' ), E'[\\\\r]+', ' ', 'g' ), E'[\\\\t]+', ' ', 'g' ), E'[\\\\cA]+', ' ', 'g' ), E'[\\\\ca]+', ' ', 'g' ) as %s".format(x,x)
     )
yearDF.selectExpr(regExpr:_*)

但是它给了我一个编译错误:Type mismatch, expected: Seq[String], actual: Array[Any]

我不能使用yearDF.columns.map,因为这将作用于所有列,并且 我无法在这里正确地形成逻辑。 谁能让我知道如何在数据框yearDF上仅将上述正则表达式应用于String类型的列吗?

2 个答案:

答案 0 :(得分:1)

这是因为yearDF.selectExpr(regExpr:_*)期望regExpr是String的Seq,而regExpr是Array [Any]。好的,您在消息中看到的。但是为什么是Array [Any]?

查看地图功能。对于架构中的每个字段,您正在映射:  -每个具有StringType的列都将包含正则表达式  -其他情况->无。

顺便说一句,请使用org.apache.spark.sql.types.StringTypeString

因此,改为:

val regExpr = yearDF.schema.fields
    .map(x => 
        if (x.dataType == StringType) 
              "regexp_replace(regexp_replace(regexp_replace(regexp_replace(regexp_replace(%s, E'[\\\\n]+', ' ', 'g' ), E'[\\\\r]+', ' ', 'g' ), E'[\\\\t]+', ' ', 'g' ), E'[\\\\cA]+', ' ', 'g' ), E'[\\\\ca]+', ' ', 'g' ) as %s".format(x.name, x.name)
        else x.name
     )
yearDF.selectExpr(regExpr:_*)

答案 1 :(得分:0)

在将regex_replace()仅应用于数据帧的字符串列时,我也遇到了类似的问题。 诀窍是制作regEx模式(在我的情况下为“模式”),该模式可在双引号内进行解析并应用转义字符。

val pattern="\"\\\\\\\\[\\\\\\\\x{FFFD}\\\\\\\\x{0}\\\\\\\\x{1F}\\\\\\\\x{81}\\\\\\\\x{8D}\\\\\\\\x{8F}\\\\\\\\x{90}\\\\\\\\x{9D}\\\\\\\\x{A0}\\\\\\\\x{0380}\\\\\\\\]\""

val regExpr = parq_out_df_temp.schema.fields.map(x => 
if(x.dataType == StringType){s"regexp_replace(%s, $pattern,'') as %s".format(x.name,x.name)} 
else x.name)

val parq_out=parq_out_df_temp.selectExpr(regExpr:_*)

这对我来说很好!