我将spark sql函数arrays_zip与flatten结合使用,将数据从相同长度的内部数组的结构数组转换为结构数组。 printSchema恰好显示了我想要的。但是,无论Parquet还是Avro格式,df输出都会丢失原始列名,并用通用列名“ 0”,“ 1”,“ 2”等替换它们。我喜欢输出原始列名。
不透露我公司的业务。以下是相似但简化的示例。
scala> c2.printSchema
root
|-- cal: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- month: array (nullable = true)
| | | |-- element: string (containsNull = true)
| | |-- num: array (nullable = true)
| | | |-- element: long (containsNull = true)
scala> c2.show(false)
+----------------------------------------------+
|cal |
+----------------------------------------------+
|[[[Jan, Feb, Mar], [1, 2, 3]], [[April], [4]]]|
+----------------------------------------------+
我喜欢转换为
scala> newC2.show(false)
+------------------------------------------+
|cal |
+------------------------------------------+
|[[Jan, 1], [Feb, 2], [Mar, 3], [April, 4]]|
+------------------------------------------+
with
scala> newC2.printSchema
root
|-- cal: array (nullable = true)
| |-- element: struct (containsNull = false)
| | |-- month: string (nullable = true)
| | |-- num: long (nullable = true)
我知道arrays_zip仅适用于顶级阵列。因此,我将它们压平到最高水平。以下代码在此示例中有效
val newC2 = c2.withColumn("month", flatten(col("cal.month"))).withColumn("num", flatten(col("cal.num"))).withColumn("cal", arrays_zip(col("month"), col("num"))).drop("month", "num")
它准确地生成我想要的数据和架构。但是,它通常使用“ 0”,“ 1”,“ 2”等输出所有列。
newC2.write.option("header", false).parquet("c2_parquet")
我尝试了另一个示例,该示例在顶层具有month数组和num数组的原始数据。我可以在不拉平的情况下使用arrays_zip并获得与所示相同的架构和数据。但是,在这种情况下,它会正确输出原始字段名称。
我尝试添加别名以拼合数据。那行不通。我什至尝试操纵列(假设字段存储arrays_zip的结果为“压缩”
val columns: Array[Column] = inner.fields.map(_.name).map{x => col("zipped").getField(x).alias(x)}
val newB3 = newB2.withColumn("b", array(struct(columns:_*))).drop("zipped")
最终生成原始架构('month',字符串数组和“ num”,long数组)。
要重复该问题,可以使用json输入
"cal":[{"month":["Jan","Feb","Mar"],"num":[1,2,3]},{"month":["April"],"num":[4]}]}
以下json用于顶级arrays_zip
{"month":["Jan","Feb","Mar"],"num":[1,2,3]}
Spark如何在内部决定要使用哪些字段名称?我如何使它工作?请告知。
答案 0 :(得分:0)
从Spark 2.4开始,可以使用高阶函数来实现模式转换。在Scala中,查询如下所示:
import org.apache.spark.sql.functions.{expr, flatten}
val result = df
.withColumn("cal", flatten(expr("TRANSFORM(cal, x -> zip_with(x.month, x.num, (month, num) -> (month,num)))")))
在应用示例数据后,我得到以下模式:
result.printSchema()
root
|-- cal: array (nullable = true)
| |-- element: struct (containsNull = false)
| | |-- month: string (nullable = true)
| | |-- num: long (nullable = true)