Я использовал функции spark sql arrayys_zip в сочетании с flatten для преобразования данных из массива структуры внутреннего массива той же длины в массив структуры. printSchema показывает именно то, что я хочу. Однако при выводе df исходные имена столбцов были потеряны и они были заменены общим именем столбца «0», «1», «2» и т. Д. Независимо от формата Parquet или Avro. Мне нравится выводить оригинальные имена столбцов.
Не раскрывать бизнес моей компании. Ниже приведены похожие, но очень упрощенные примеры.
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)
Я знаю, что array_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")
Я попробовал другой пример, который имеет исходные данные массива месяцев и массива чисел на верхнем уровне. Я могу array_zip без сглаживания и получить ту же схему и показанные данные. Однако в этом случае он правильно выводит исходное имя поля.
Я попытался добавить псевдоним для сглаживания данных. Это не работает. Я даже пробовал манипулировать столбцами вроде (предположим, что в полевом хранилище результат array_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")
В итоге создается исходная схема («месяц», массив строк и «число», массив длинных значений).
Чтобы продублировать проблему, вы можете использовать ввод json
"cal":[{"month":["Jan","Feb","Mar"],"num":[1,2,3]},{"month":["April"],"num":[4]}]}
следующий json предназначен для array_zip верхнего уровня
{"month":["Jan","Feb","Mar"],"num":[1,2,3]}
Как Spark внутренне решает, какие имена полей использовать? Как заставить его работать? Пожалуйста, порекомендуйте.