如何在Apache Spark 2.3.1中映射/转换ArrayType中的每个元素

时间:2018-08-10 07:29:15

标签: scala apache-spark dataframe apache-spark-sql

简短版本:如何将嵌套数组中的每个条目转换为其他内容(例如struct)?

如何转换:

+---------+
|column_a |
+---------+
|[A, B, C]|
|[D, E]   |
|[F]      |
|[]       |
+---------+

对此:

+---------+---------------------------+
|column_a |column_b                   |
+---------+---------------------------+
|[A, B, C]|[[A, aa], [B, bb], [C, cc]]|
|[D, E]   |[[D, dd], [E, ee]]         |
|[F]      |[[F, ff]]                  |
|[]       |[]                         |
+---------+---------------------------+

长版:

假设存在一个DataFrame,其中的column_A包含字符串数组:

val schema = Seq(
   StructField("column_a", ArrayType(StringType), true)
)
val data = Seq(
   Row(Array("A", "B", "C")),
   Row(Array("D", "E")),
   Row(Array("F")),
   Row(Array())
)
val df = spark.createDataFrame(
   spark.sparkContext.parallelize(data),
   StructType(schema)
)
df.show(false)

+---------+
|column_a |
+---------+
|[A, B, C]|
|[D, E]   |
|[F]      |
|[]       |
+---------+

我想以以下DataFrame结尾:

val schema2 = List(
  StructField("column_a", ArrayType(StringType)),
  StructField("column_b", ArrayType(StructType(
  Array(StructField("colA", StringType), StructField("colB", StringType))
  )))
)

val data2 = Seq(
  Row(Array("A", "B", "C"),
    Array(Row("A", "aa"), Row("B", "bb"), Row("C", "cc"))),
  Row(Array("D", "E"),
    Array(Row("D", "dd"), Row("E", "ee"))),
  Row(Array("F"),
    Array(Row("F", "ff"))),
  Row(Array(), Array())
)

val df2 = spark.createDataFrame(
  spark.sparkContext.parallelize(data2),
  StructType(schema2)
)

df2.show(false)

+---------+---------------------------+
|column_a |column_b                   |
+---------+---------------------------+
|[A, B, C]|[[A, aa], [B, bb], [C, cc]]|
|[D, E]   |[[D, dd], [E, ee]]         |
|[F]      |[[F, ff]]                  |
|[]       |[]                         |
+---------+---------------------------+

column_b中的值应使用column_A条目生成。对于column_A中的每个条目,column_B中都有一个新结构。

Spark 2.3.1中实现此目的的有效方法是什么?

(我希望使用DSL,尽管可以接受SQL。)

2 个答案:

答案 0 :(得分:2)

您可以使用Localtime= time.asctime(time.localtime(time.time())) Print(localtime) 来实现:

UDF

这将给出:

val transform = udf((arr: Seq[String]) => {
  arr.map(v => (v, v.toLowerCase()*2))
})

df.withColumn("column_b", transform($"column_a")).show(false)

答案 1 :(得分:0)

Python版本

from pyspark.sql.functions import udf
from pyspark.sql.types import ArrayType, StringType

def my_func(arr):
    return list(map(lambda s: s.lower()*2, arr))

transform = udf(my_func, ArrayType(StringType()))
df.withColumn("column_b", transform("column_a"))