如何在不使用Scala case类的情况下为CSV文件指定模式?

如何在不使用Scala case类的情况下为CSV文件指定模式?,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我正在将CSV文件加载到数据框中,如下所示 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

我正在将CSV文件加载到数据框中,如下所示

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)

如何将
age
列更改为
Int
类型?

在这种情况下,您可以使用自定义项:

步骤1:创建一个将字符串转换为Int的自定义项

val stringToIntUDF = udf((value:String)=>value.toInt)
步骤2:将此自定义项应用于要转换的列

val updatedDF = df.withColumns("age",stringToIntUDF(df("age")))
updatedDF.printSchema
这会给你你想要的结果

如果您只是想从CSV文件推断您的模式。那么@vdep解决方案似乎是在做正确的事情

val df=spark.read
  .format("org.apache.spark.csv")
  .option("header",true)
  .option("inferSchema", "true") // <-- HERE
  .csv("/home/cloudera/Book1.csv")
val df=spark.read
.format(“org.apache.spark.csv”)
.选项(“标题”,真)

.option(“inferSchema”,“true”)/有
inferSchema
选项可通过以下方式自动识别变量类型:

val df=spark.read
  .format("org.apache.spark.csv")
  .option("header", true)
  .option("inferSchema", true) // <-- HERE
  .csv("/home/cloudera/Book1.csv")
val df=spark.read
.format(“org.apache.spark.csv”)
.选项(“标题”,真)

.option(“inferSchema”,true)/给定
val spark=SparkSession.builder().getOrCreate()
我猜您使用的是spark 2.x


首先,请注意Spark 2.x本机支持CSV格式,因此不需要通过其长名称指定格式,即
org.apache.Spark.CSV
,而只需
CSV

spark.read.format("csv")...
// note that I removed format("csv")
spark.read.option("header", true).csv("/home/cloudera/Book1.csv")
由于您使用了
csv
运算符,因此csv格式是隐含的,因此您可以跳过/删除
格式(“csv”)


有了它,您就有了很多选择,但我强烈建议使用case类来处理模式。如果您想知道如何在Spark 2.0中实现,请参阅最后一个解决方案

铸造操作工 你可以用接线员

scala> Seq("1").toDF("str").withColumn("num", 'str cast "int").printSchema
root
 |-- str: string (nullable = true)
 |-- num: integer (nullable = true)
使用StructType 您还可以使用自己手工制作的模式,如下所示:

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)
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)
模式DSL 最近我发现非常有趣的是所谓的模式DSL。使用
StructType
StructField
构建的上述架构可以按如下方式重新编写:

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)
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)
编码器 编码器非常容易使用,以至于很难相信您不需要它们,即使只是构建模式而不处理
StructType
StructField
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)

很抱歉,我无法正确理解这个问题,我以为您只是想将年龄从字符串更改为Int,因此提供了此解决方案!