【问题标题】:Array manipulation in Spark, ScalaSpark、Scala 中的数组操作
【发布时间】:2020-01-04 03:39:55
【问题描述】:

我是 scala、spark 的新手,在尝试从一些玩具数据帧中学习时遇到了问题。

我有一个包含以下两列的数据框:

 Name_Description        Grade

Name_Description 是一个数组,Grade 只是一个字母。这是我遇到问题的 Name_Description。在 Spark 上使用 scala 时,我正在尝试更改此列。

名称描述不是一个固定大小的数组。可能是这样的

['asdf_布兰登', 'Ca%abc%rd'] ['fthhhhChris', 'Rock', '是%abc%man']

唯一的问题如下:

 1. the first element of the array ALWAYS has 6 garbage characters, so the real meaning starts at 7th character.

 2. %abc% randomly pops up on elements, so I wanna erase them.

有没有办法在 Scala 中实现这两件事?例如,我只想

 ['asdf_ Brandon', 'Ca%abc%rd'], ['fthhhhChris', 'Rock', 'is the %abc%man']

改成

['Brandon', 'Card'], ['Chris', 'Rock', 'is the man']

【问题讨论】:

  • 那么Name_Description 是一个字符串数组吗?
  • @KrzysztofAtłasik Name_Description 的每一行都是一个字符串数组。 ['asdf_ Brandon', 'Ca%abc%rd'] ['fthhhhChris', 'Rock', 'is the %abc%man'] 代表两行Name_Description

标签: scala dataframe apache-spark


【解决方案1】:

使用标准 spark functions 可能难以实现您想要做的事情,但您可以为此定义 UDF:

val removeGarbage = udf { arr: WrappedArray[String] => 
     //in case that array is empty we need to map over option
     arr.headOption 
     //drop first 6 characters from first element, then remove %abc% from the rest
        .map(head => head.drop(6) +: arr.tail.map(_.replace("%abc%","")))
        .getOrElse(arr)  
}

那么你只需要在你的Name_Description 列上使用这个UDF:

val df = List(
    (1, Array("asdf_ Brandon", "Ca%abc%rd")), 
    (2, Array("fthhhhChris", "Rock", "is the %abc%man"))
).toDF("Grade", "Name_Description")

df.withColumn("Name_Description", removeGarbage($"Name_Description")).show(false)

显示打印:

+-----+-------------------------+
|Grade|Name_Description         |
+-----+-------------------------+
|1    |[Brandon, Card]          |
|2    |[Chris, Rock, is the man]|
+-----+-------------------------+

【讨论】:

    【解决方案2】:

    我们总是被鼓励使用 spark sql 函数并尽可能避免使用 UDF。我有一个简化的解决方案,它利用了 spark sql 函数。

    请在下面找到我的方法。希望对您有所帮助。

    val d = Array((1,Array("asdf_ Brandon","Ca%abc%rd")),(2,Array("fthhhhChris", "Rock", "is the %abc%man")))
    
    val df = spark.sparkContext.parallelize(d).toDF("Grade","Name_Description")
    

    这就是我创建输入数据框的方式。

    df.select('Grade,posexplode('Name_Description)).registerTempTable("data")
    

    我们分解数组以及数组中每个元素的位置。我注册了数据框,以便使用查询来生成所需的输出。

    spark.sql("""select Grade, collect_list(Names) from (select Grade,case when pos=0 then substring(col,7) else replace(col,"%abc%","") end as Names from data) a group by Grade""").show
    

    此查询将给出所需的输出。希望这会有所帮助。

    【讨论】:

    • 很好地使用了posexplode,但我认为group by Grade 是不正确的。除非Grade 是行标识列,否则将其与collect_list 分组可以将原本不相关的名称组件组合成一个数组。
    猜你喜欢
    • 1970-01-01
    • 2023-04-07
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多