Spark unionAll несколько кадров данных

для набора кадров данных

val df1 = sc.parallelize(1 to 4).map(i => (i,i*10)).toDF("id","x")
val df2 = sc.parallelize(1 to 4).map(i => (i,i*100)).toDF("id","y")
val df3 = sc.parallelize(1 to 4).map(i => (i,i*1000)).toDF("id","z")

для объединения всех их я делаю

df1.unionAll(df2).unionAll(df3)

есть ли более элегантный и масштабируемый способ сделать это для любого количества таблиц данных, например,

Seq(df1, df2, df3) 

2 ответов


самое простое решение -reduce С union (unionAll в Spark

val dfs = Seq(df1, df2, df3)
dfs.reduce(_ union _)

это относительно лаконично и не должно перемещать данные из хранилища вне кучи но расширяет родословную с каждым Союзом требуется нелинейное время для выполнения анализа плана. что может быть проблемой, если вы попытаетесь объединить большое количество DataFrames.

вы также можете конвертировать в RDDs и использовать SparkContext.union:

dfs match {
  case h :: Nil => Some(h)
  case h :: _   => Some(h.sqlContext.createDataFrame(
                     h.sqlContext.sparkContext.union(dfs.map(_.rdd)),
                     h.schema
                   ))
  case Nil  => None
}

держит родословная short стоимость анализа низкая, но в остальном она менее эффективна, чем слияние DataFrames напрямую.


для pyspark вы можете сделать следующее:

from functools import reduce
from pyspark.sql import DataFrame

dfs = [df1,df2,df3]
df = reduce(DataFrame.unionAll, dfs)

также ничего не стоит, чтобы порядок столбцов в кадрах данных был одинаковым для этого. Это может молча дать неожиданные результаты, если у вас нет правильных заказов столбцов!!

Если вы используете pyspark 2.3 или выше, вы можете использовать unionByName, поэтому вам не нужно переупорядочивать столбцы.