【问题标题】:Spark - remove special characters from rows Dataframe with different column typesSpark - 从具有不同列类型的行数据框中删除特殊字符
【发布时间】:2017-08-07 23:03:30
【问题描述】:

假设我有一个包含许多列的数据框,有些是 string 类型,有些是 int 类型,有些是 map 类型。

例如 字段/列types: stringType|intType|mapType<string,int>|...

|--------------------------------------------------------------------------
|  myString1      |myInt1|  myMap1                                              |...
|--------------------------------------------------------------------------
|"this_is_#string"| 123 |{"str11_in#map":1,"str21_in#map":2, "str31_in#map": 31}|...
|"this_is_#string"| 456 |{"str12_in#map":1,"str22_in#map":2, "str32_in#map": 32}|...
|"this_is_#string"| 789 |{"str13_in#map":1,"str23_in#map":2, "str33_in#map": 33}|...
|--------------------------------------------------------------------------

我想从 String 和 Map 类型的所有列中删除一些字符,例如 '_' 和 '#' 所以结果 Dataframe/RDD 将是:

|------------------------------------------------------------------------
|myString1     |myInt1|     myMap1|...                                 |
|------------------------------------------------------------------------
|"thisisstring"| 123 |{"str11inmap":1,"str21inmap":2, "str31inmap": 31}|...
|"thisisstring"| 456 |{"str12inmap":1,"str22inmap":2, "str32inmap": 32}|...
|"thisisstring"| 789 |{"str13inmap":1,"str23inmap":2, "str33inmap": 33}|...
|-------------------------------------------------------------------------

我不确定将 Dataframe 转换为 RDD 并使用它或在 Dataframe 中执行工作是否更好。

另外,不确定如何以最佳方式处理具有不同列类型的正则表达式(我在唱 scala)。 我想对这两种类型(字符串和映射)的所有列执行此操作,尽量避免使用如下列名称:

def cleanRows(mytabledata: DataFrame): RDD[String] = {

//this will do the work for a specific column (myString1) of type string
val oneColumn_clean = mytabledata.withColumn("myString1", regexp_replace(col("myString1"),"[_#]",""))

       ...
//return type can be RDD or Dataframe...
}

是否有任何简单的解决方案来执行此操作? 谢谢

【问题讨论】:

    标签: regex scala apache-spark dataframe rdd


    【解决方案1】:

    一种选择是定义两个udf分别处理字符串类型列和映射类型列:

    import org.apache.spark.sql.functions.udf
    val df = Seq(("this_is#string", 3, Map("str1_in#map" -> 3))).toDF("myString", "myInt", "myMap")
    df.show
    +--------------+-----+--------------------+
    |      myString|myInt|               myMap|
    +--------------+-----+--------------------+
    |this_is#string|    3|Map(str1_in#map -...|
    +--------------+-----+--------------------+
    

    1) Udf 处理字符串类型列:

    def remove_string: String => String = _.replaceAll("[_#]", "")
    def remove_string_udf = udf(remove_string)
    

    2) 处理 Map 类型列的 Udf:

    def remove_map: Map[String, Int] => Map[String, Int] = _.map{ case (k, v) => k.replaceAll("[_#]", "") -> v }
    def remove_map_udf = udf(remove_map)
    

    3) 将udfs应用到相应的列进行清理:

    df.withColumn("myString", remove_string_udf($"myString")).
       withColumn("myMap", remove_map_udf($"myMap")).show
    
    +------------+-----+-------------------+
    |    myString|myInt|              myMap|
    +------------+-----+-------------------+
    |thisisstring|    3|Map(str1inmap -> 3)|
    +------------+-----+-------------------+
    

    【讨论】:

    • 嗨@Psidom,可能感谢您的提示。这似乎工作正常,但是这样,需要映射 Dataframe 中的所有列。正在寻找更多通用用法。也许这不是那么直截了当..无论如何投票,tx
    • 嗨@Psidom,通过任何更改是否有办法创建def remove_map:.. 的模板函数,例如:def remove_map[T]: Map[String, T] => Map[String, T] = 我尝试了几种方法,但其中任何一种都有效。这可以避免使用多种功能,Map<String, NumericField> 的每个组合一个。
    • 我不确定这是否可能。可能值得提出一个单独的问题,看看您是否可以得出任何信息丰富的答案。
    • 谢谢,我做了,但没有回应..stackoverflow.com/questions/42856601/…
    猜你喜欢
    • 2018-04-16
    • 2023-03-25
    • 1970-01-01
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    相关资源
    最近更新 更多