web-dev-qa-db-fra.com

Comment spécifier un schéma pour un fichier CSV sans utiliser Scala classe de cas?

Je charge un fichier CSV dans un DataFrame comme ci-dessous.

val conf=new SparkConf().setAppName("dataframes").setMaster("local")
val sc=new SparkContext(conf)
val spark=SparkSession.builder().getOrCreate()
import spark.implicits._

val df = spark.
  read.  
  format("org.Apache.spark.csv").
  option("header", true).
  csv("/home/cloudera/Book1.csv")
scala> df.printSchema()
root
 |-- name: string (nullable = true)
 |-- address: string (nullable = true)
 |-- age: string (nullable = true)

Comment changer la colonne age pour qu'elle soit de type Int?

15
Ishan Kumar

Il y a inferSchema option pour reconnaître automatiquement le type de la variable par:

val df=spark.read
  .format("org.Apache.spark.csv")
  .option("header", true)
  .option("inferSchema", true) // <-- HERE
  .csv("/home/cloudera/Book1.csv")

spark-csv était à l'origine une bibliothèque externe de databricks, mais incluse dans le noyau spark from spark version 2.0 onwards. You can refer to documentation on the library's page github pour trouver les options disponibles.

20
vdep

Étant donné val spark=SparkSession.builder().getOrCreate() I devinez vous utilisez Spark 2.x.


Tout d'abord, veuillez noter que Spark 2.x a un support natif pour le format CSV et en tant que tel ne nécessite pas de spécifier le format par son nom long, c'est-à-dire org.Apache.spark.csv, Mais juste csv.

spark.read.format("csv")...

Puisque vous utilisez l'opérateur csv, le format CSV est implicite et vous pouvez donc ignorer/supprimer format("csv").

// note that I removed format("csv")
spark.read.option("header", true).csv("/home/cloudera/Book1.csv")

Avec cela, vous avez beaucoup d'options, mais je recommande fortement d'utiliser une classe de cas pour ... juste le schéma. Voir la dernière solution si vous êtes curieux de savoir comment le faire dans Spark 2.0.

opérateur de plâtre

Vous pouvez utiliser l'opérateur cast .

scala> Seq("1").toDF("str").withColumn("num", 'str cast "int").printSchema
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = true)

Utilisation de StructType

Vous pouvez également utiliser votre propre schéma artisanal avec StructType et StructField comme suit:

import org.Apache.spark.sql.types._    
val schema = StructType(
  StructField("str", StringType, true) :: 
  StructField("num", IntegerType, true) :: Nil)

scala> schema.printTreeString
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = true)

val q = spark.
  read.
  option("header", true).
  schema(schema).
  csv("numbers.csv")
scala> q.printSchema
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = true)

Schéma DSL

Ce que j'ai trouvé assez intéressant récemment était ce qu'on appelle Schéma DSL . Le schéma ci-dessus construit à l'aide de StructType et StructField peut être réécrit comme suit:

import org.Apache.spark.sql.types._
val schema = StructType(
  $"str".string ::
  $"num".int :: Nil) 
scala> schema.printTreeString
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = true)

// or even
val schema = new StructType().
  add($"str".string).
  add($"num".int)
scala> schema.printTreeString
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = true)

Encodeurs

Les encodeurs sont si faciles à utiliser qu'il est difficile de croire que vous ne pouvez pas les vouloir, ne serait-ce que pour construire un schéma sans traiter avec StructType, StructField et DataType.

// Define a business object that describes your dataset
case class MyRecord(str: String, num: Int)

// Use Encoders object to create a schema off the business object
import org.Apache.spark.sql.Encoders    
val schema = Encoders.product[MyRecord].schema
scala> schema.printTreeString
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = false)
29
Jacek Laskowski