【问题标题】:Spark - split a string column escaping the delimiter in one partSpark - 拆分一个字符串列,在一部分中转义分隔符
【发布时间】:2018-04-26 05:20:57
【问题描述】:

我有一个包含两个字符串列(术语、代码)的 CSV 文件。代码列具有特殊格式[num]-[two_letters]-[text],其中text 还可以包含破折号-。我想使用 Spark 将这个文件读入一个正好有四列(term、num、two_letters、text)的数据框。

Input
+---------------------------------+
|  term  |          code          |
+---------------------------------+
| term01 |    12-AB-some text     |
| term02 | 130-CD-some-other-text |
+---------------------------------+


Output
+------------------------------------------+
|  term  | num | letters |       text      |
+------------------------------------------+
| term01 | 12  |   AB    |   some text     |
| term02 | 130 |   CD    | some-other-text |
+------------------------------------------+

当code 部分中没有破折号时,我可以将code 列拆分为三列,但是我如何才能实现解决所有情况的解决方案(例如将两个破折号后的所有文本放入一列)?

将一列分成三列的代码在答案here中得到了很好的说明

【问题讨论】:

    标签: scala apache-spark


    【解决方案1】:

    这是regexp_extract 的一个选项:

    val df = Seq(("term01", "12-AB-some text"), ("term02", "130-CD-some-other-text")).toDF("term", "code")
    
    // define the pattern that matches the string column
    val p = "([0-9]+)-([a-zA-Z]{2})-(.*)"
    // p: String = ([0-9]+)-([a-zA-Z]{2})-(.*)
    
    // define the map from new column names to the group index in the pattern
    val cols = Map("num" -> 1, "letters" -> 2, "text" -> 3)
    // cols: scala.collection.immutable.Map[String,Int] = Map(num -> 1, letters -> 2, text -> 3)
    
    // create the new columns on data frame
    cols.foldLeft(df){ 
        case (df, (colName, groupIdx)) => df.withColumn(colName, regexp_extract($"code", p, groupIdx)) 
    }.drop("code").show
    
    +------+---+-------+---------------+
    |  term|num|letters|           text|
    +------+---+-------+---------------+
    |term01| 12|     AB|      some text|
    |term02|130|     CD|some-other-text|
    +------+---+-------+---------------+
    

    【讨论】:

      【解决方案2】:

      这就是我利用 UDF 的方式:

      case class MyData(num: Int, letters: String, text: String)
      def udfSplit = udf(
        (input: String) => { 
          val res = input.split("-", 3) // limit=3 => pattern applied at most n - 1 times
          MyData(res(0).toInt, res(1), res(2))
        }
      )
      
      val df = spark.createDataFrame(
          Seq(
            ("term01", "12-AB-some text"), 
            ("term02", "130-CD-some-other-text")
          )
      ).toDF("term", "code")
      df.show(false)
      +------+----------------------+
      |term  |code                  |
      +------+----------------------+
      |term01|12-AB-some text       |
      |term02|130-CD-some-other-text|
      +------+----------------------+
      
      val res = df.withColumn("code", udfSplit($"code"))
      res.show(false)
      +------+------------------------+
      |term  |code                    |
      +------+------------------------+
      |term01|[12,AB,some text]       |
      |term02|[130,CD,some-other-text]|
      +------+------------------------+
      
      res.printSchema
      root
       |-- term: string (nullable = true)
       |-- code: struct (nullable = true)
       |    |-- num: integer (nullable = false)
       |    |-- letters: string (nullable = true)
       |    |-- text: string (nullable = true)
      
      res.select("term", "code.*").show(false)
      +------+---+-------+---------------+
      |term  |num|letters|text           |
      +------+---+-------+---------------+
      |term01|12 |AB     |some text      |
      |term02|130|CD     |some-other-text|
      +------+---+-------+---------------+
      

      【讨论】:

      • 感谢您提供非常明确的解决方案。也解决了这个问题。
      猜你喜欢
      • 1970-01-01
      • 2017-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多