如何创建一个指定模式的空数据框?

118

我想在Scala中创建一个具有指定模式的DataFrame。我尝试使用JSON读取(我指的是读取空文件),但我认为那不是最佳实践。


我能够按照格式要求进行翻译,保留了HTML标签,并且使内容通俗易懂。
10个回答

155

假设您想要一个具有以下架构的数据框:

root
 |-- k: string (nullable = true)
 |-- v: integer (nullable = false)

您只需为数据框定义模式,并使用空的RDD [Row]

import org.apache.spark.sql.types.{
    StructType, StructField, StringType, IntegerType}
import org.apache.spark.sql.Row

val schema = StructType(
    StructField("k", StringType, true) ::
    StructField("v", IntegerType, false) :: Nil)

// Spark < 2.0
// sqlContext.createDataFrame(sc.emptyRDD[Row], schema) 
spark.createDataFrame(sc.emptyRDD[Row], schema)

PySpark 的等价物几乎完全相同:

from pyspark.sql.types import StructType, StructField, IntegerType, StringType

schema = StructType([
    StructField("k", StringType(), True), StructField("v", IntegerType(), False)
])

# or df = sc.parallelize([]).toDF(schema)

# Spark < 2.0 
# sqlContext.createDataFrame([], schema)
df = spark.createDataFrame([], schema)

使用隐式编码器(仅适用于Scala)处理TupleProduct类型:
import spark.implicits._

Seq.empty[(String, Int)].toDF("k", "v")

或者 case class:

case class KV(k: String, v: Int)

Seq.empty[KV].toDF

或者
spark.emptyDataset[KV].toDF

1
这是最合适的答案 - 完整的,如果您想快速复制现有数据集的模式也非常有用。我不知道为什么它没有被接受。 - Lucas Lima
如何使用特质而不是案例类创建df:https://dev59.com/questions/Dr3pa4cB1Zd3GeqPiKNd - supernatural

47

从Spark 2.0.0开始,您可以执行以下操作。

Case Class

让我们定义一个名为Person的案例类:

scala> case class Person(id: Int, name: String)
defined class Person

导入 spark SparkSession 隐式 Encoders:

scala> import spark.implicits._
import spark.implicits._

使用SparkSession创建一个空的Dataset [Person]

scala> spark.emptyDataset[Person]
res0: org.apache.spark.sql.Dataset[Person] = [id: int, name: string]

Schema DSL

您还可以使用模式"DSL"(请参见org.apache.spark.sql.ColumnName中的DataFrames支持函数)。

scala> val id = $"id".int
id: org.apache.spark.sql.types.StructField = StructField(id,IntegerType,true)

scala> val name = $"name".string
name: org.apache.spark.sql.types.StructField = StructField(name,StringType,true)

scala> import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.types.StructType

scala> val mySchema = StructType(id :: name :: Nil)
mySchema: org.apache.spark.sql.types.StructType = StructType(StructField(id,IntegerType,true), StructField(name,StringType,true))

scala> import org.apache.spark.sql.Row
import org.apache.spark.sql.Row

scala> val emptyDF = spark.createDataFrame(sc.emptyRDD[Row], mySchema)
emptyDF: org.apache.spark.sql.DataFrame = [id: int, name: string]

scala> emptyDF.printSchema
root
 |-- id: integer (nullable = true)
 |-- name: string (nullable = true)

嗨,编译器说我的模块中不存在 spark.emptyDataset,该怎么使用它?有一些(正确的)类似于(不正确的)val df = apache.spark.emptyDataset[RawData] 吗? - Peter Krauss
@PeterKrauss spark 是使用 SparkSession.builder 创建的值,不是 org.apache.spark 包的一部分。有两个正在使用的 spark 名称。它是你在 spark-shell 中默认可用的 spark - Jacek Laskowski
1
谢谢Jacek。我已经更正了:SparkSession.builder对象是从第一次通用初始化中作为参数传递的(似乎是最好的解决方案),现在正在运行。 - Peter Krauss
有没有一种方法可以使用trait而不是case class创建空的dataframe: https://dev59.com/Dr3pa4cB1Zd3GeqPiKNd - supernatural

5

创建空数据集所需的Java版本:

public Dataset<Row> emptyDataSet(){

    SparkSession spark = SparkSession.builder().appName("Simple Application")
                .config("spark.master", "local").getOrCreate();

    Dataset<Row> emptyDataSet = spark.createDataFrame(new ArrayList<>(), getSchema());

    return emptyDataSet;
}

public StructType getSchema() {

    String schemaString = "column1 column2 column3 column4 column5";

    List<StructField> fields = new ArrayList<>();

    StructField indexField = DataTypes.createStructField("column0", DataTypes.LongType, true);
    fields.add(indexField);

    for (String fieldName : schemaString.split(" ")) {
        StructField field = DataTypes.createStructField(fieldName, DataTypes.StringType, true);
        fields.add(field);
    }

    StructType schema = DataTypes.createStructType(fields);

    return schema;
}

3

在这里,您可以使用Scala中的StructType创建模式,并传递空RDD,以便创建空表。 以下代码是相同的。

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql._
import org.apache.spark.sql.Row
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.types.StructField
import org.apache.spark.sql.types.IntegerType
import org.apache.spark.sql.types.BooleanType
import org.apache.spark.sql.types.LongType
import org.apache.spark.sql.types.StringType



//import org.apache.hadoop.hive.serde2.objectinspector.StructField

object EmptyTable extends App {
  val conf = new SparkConf;
  val sc = new SparkContext(conf)
  //create sparksession object
  val sparkSession = SparkSession.builder().enableHiveSupport().getOrCreate()

  //Created schema for three columns 
   val schema = StructType(
    StructField("Emp_ID", LongType, true) ::
      StructField("Emp_Name", StringType, false) ::
      StructField("Emp_Salary", LongType, false) :: Nil)

      //Created Empty RDD 

  var dataRDD = sc.emptyRDD[Row]

  //pass rdd and schema to create dataframe
  val newDFSchema = sparkSession.createDataFrame(dataRDD, schema)

  newDFSchema.createOrReplaceTempView("tempSchema")

  sparkSession.sql("create table Finaltable AS select * from tempSchema")

}

3
import scala.reflect.runtime.{universe => ru}
def createEmptyDataFrame[T: ru.TypeTag] =
    hiveContext.createDataFrame(sc.emptyRDD[Row],
      ScalaReflection.schemaFor(ru.typeTag[T].tpe).dataType.asInstanceOf[StructType]
    )
  case class RawData(id: String, firstname: String, lastname: String, age: Int)
  val sourceDF = createEmptyDataFrame[RawData]

3

这对于测试目的非常有用。

Seq.empty[String].toDF()

如何从Trait创建空DF:https://dev59.com/questions/Dr3pa4cB1Zd3GeqPiKNd - supernatural

2
这里有一个解决方案,可以在pyspark 2.0.0或更高版本中创建一个空的数据框架。
from pyspark.sql import SQLContext
sc = spark.sparkContext
schema = StructType([StructField('col1', StringType(),False),StructField('col2', IntegerType(), True)])
sqlContext.createDataFrame(sc.emptyRDD(), schema)

0
我想添加以下尚未提及的语法:
Seq[(String, Integer)]().toDF("k", "v")

它清楚地表明()部分是用于值的。它是空的,因此数据框为空。

这种语法对于手动添加null值也很有益。它只是起作用,而其他选项要么不起作用,要么过于冗长。


0
我有一个特殊的需求,我已经有了一个数据框,但是在给定某个条件的情况下,我必须返回一个空的数据框,所以我返回了df.limit(0)

-3

截至Spark 2.4.3版本

val df = SparkSession.builder().getOrCreate().emptyDataFrame

9
这并未解决问题中的模式部分。 - Andrew Sklyarevsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接