RUDE

Spark Scala - объединение столбцов в строки в определенном порядке

Хорошо, у меня есть таблица с определениями столбцов и соответствующими порядковыми позициями. Я создаю среду ETL на основе метаданных, используя Spark (scala). У меня есть таблица, содержащая следующую информацию:

  • имя таблицы
  • имя столбца
  • тип данных
  • порядковый номер

Мне нужно построить оператор CREATE TABLE из этих данных. Ничего страшного, правда? Я попробовал стандартный ответ:

var metadatadef = spark.sql("SELECT tablename, columnname, datatype, ordinalposition FROM metadata")
    .withColumn("columndef", concat($"columnname", lit(" "), $"datatype"))
    .sort($"tablename", $"ordinalposition")
    .groupBy("tablename")
    .agg(concat_ws(", ", collect_list($"columndef")).as("columndefs"))

Но вызов sort () здесь, похоже, игнорируется. Или между collect_list () и concat_ws () он перетасовывается. Учитывая исходные данные вроде этого:

+-----------+--------------+---------------+-----------------+
| tablename | columnname   | datatype      | ordinalposition |
+ ----------+--------------+---------------+-----------------+
| table1    | IntColumn    | int           | 0               |
| table2    | StringColumn | string        | 2               |
| table1    | StringColumn | string        | 2               |
| table2    | IntColumn    | int           | 0               |
| table1    | DecColumn    | decimal(15,2) | 1               |
| table2    | DecColumn    | decimal(15,2) | 1               |
+-----------+--------------+---------------+-----------------+

Я пытаюсь получить такой вывод:

+-----------+----------------------------------------------------------------+
| tablename | columndefs                                                     |
+-----------+----------------------------------------------------------------+
| table1    | IntColumn int, DecColumn decimal(15,2), StringColumn string    |
| table2    | IntColumn int, DecColumn decimal(15,2), StringColumn string    |
+-----------+----------------------------------------------------------------+

Вместо этого я получаю что-то вроде этого:

+-----------+----------------------------------------------------------------+
| tablename | columndefs                                                     |
+-----------+----------------------------------------------------------------+
| table1    | IntColumn int, StringColumn string, DecColumn decimal(15,2)    |
| table2    | StringColumn string, IntColumn int, DecColumn decimal(15,2)    |
+-----------+----------------------------------------------------------------+

Нужно ли мне создавать UDF, чтобы обеспечить надлежащий порядок? Мне нужно, чтобы вывод помещался во фрейм данных для целей сравнения, а не просто для создания оператора CREATE TABLE.


1 091
1

Ответ:

Решено

Вы можете создать столбец struct из (ordinalposition, columndef) и применить sort_array для сортировки агрегированных columndef в желаемом порядке во время преобразования groupBy следующим образом:

import org.apache.spark.sql.functions._

val df = Seq(
  ("table1", "IntColumn", "int", "0"),
  ("table2", "StringColumn", "string", "2"),
  ("table1", "StringColumn", "string", "2"),
  ("table2", "IntColumn", "int", "0"),
  ("table1", "DecColumn", "decimal(15,2)", "1"),
  ("table2", "DecColumn", "decimal(15,2)", "1")
).toDF("tablename", "columnname", "datatype", "ordinalposition")

df.
  withColumn("columndef",
    struct($"ordinalposition", concat($"columnname", lit(" "), $"datatype").as("cdef"))
  ).
  groupBy("tablename").agg(sort_array(collect_list($"columndef")).as("sortedlist")).
  withColumn("columndefs", concat_ws(", ", $"sortedlist.cdef")).
  drop("sortedlist").
  show(false)
// +---------+-----------------------------------------------------------+
// |tablename|columndefs                                                 |
// +---------+-----------------------------------------------------------+
// |table2   |IntColumn int, DecColumn decimal(15,2), StringColumn string|
// |table1   |IntColumn int, DecColumn decimal(15,2), StringColumn string|
// +---------+-----------------------------------------------------------+