Comment créer un DataFrame vide avec un schéma spécifié?


94

Je veux créer DataFrameavec un schéma spécifié dans Scala. J'ai essayé d'utiliser JSON read (je veux dire lire un fichier vide) mais je ne pense pas que ce soit la meilleure pratique.

Réponses:


126

Supposons que vous vouliez un bloc de données avec le schéma suivant:

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

Vous définissez simplement le schéma pour un bloc de données et utilisez vide 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)

L'équivalent PySpark est presque identique:

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)

Utilisation d'encodeurs implicites (Scala uniquement) avec des Producttypes comme Tuple:

import spark.implicits._

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

ou classe de cas:

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

Seq.empty[KV].toDF

ou

spark.emptyDataset[KV].toDF

C'est la réponse la plus appropriée - complète et également utile si vous souhaitez reproduire rapidement le schéma d'un ensemble de données existant. Je ne sais pas pourquoi ce n'est pas celui qui est accepté.
Lucas Lima le

40

À partir de Spark 2.0.0, vous pouvez effectuer les opérations suivantes.

Classe de cas

Définissons une Personclasse de cas:

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

Importer sparkSparkSession implicite Encoders:

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

Et utilisez SparkSession pour créer un vide Dataset[Person]:

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

Schéma DSL

Vous pouvez également utiliser un schéma "DSL" (voir Fonctions de support pour DataFrames dans org.apache.spark.sql.ColumnName ).

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)

Salut, le compilateur dit qu'il spark.emptyDatasetn'existe pas sur mon module, comment l'utiliser? il y en a (correct) similaire à (non correct) val df = apache.spark.emptyDataset[RawData]?
Peter Krauss

@PeterKrauss sparkest la valeur que vous créez en SparkSession.builderne faisant pas partie du org.apache.sparkpackage. Il y a deux sparknoms en usage. C'est le que sparkvous avez disponible dans spark-shellla boîte.
Jacek Laskowski

1
Merci Jacek. J'ai corrigé: l'objet SparkSession.builder est passé en paramètre (semble être la meilleure solution) à partir de la première initialisation générale, est maintenant en cours d'exécution.
Peter Krauss

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

Ici, vous pouvez créer un schéma en utilisant StructType dans scala et passer le RDD vide afin que vous puissiez créer une table vide. Le code suivant est pour le même.

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")

}

2

Version Java pour créer un DataSet vide:

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;
}

1

Voici une solution qui crée un dataframe vide dans pyspark 2.0.0 ou plus.

from pyspark.sql import SQLContext
sc = spark.sparkContext
schema = StructType([StructField('col1', StringType(),False),StructField('col2', IntegerType(), True)])
sqlContext.createDataFrame(sc.emptyRDD(), schema)

0

Ceci est utile à des fins de test.

Seq.empty[String].toDF()

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.