繁体   English   中英

Spark/Scala:无法将 RDD 转换为 DF

[英]Spark/Scala: Impossible to make an RDD to DF conversion

我是 scala(2.11) 和 spark (1.6.0) 的新程序员,他试图在没有 spark-csv package 的情况下将 RDD 转换为 DF(为了练习,但也因为一些技术问题)。 在阅读了 Spark 的入门指南和 stackoverflow 的所有相关帖子后,我不知道如何使某些方法 (4) 起作用——只有一个对我有用,我不知道为什么——:

他们中任何一个的每一次帮助都将是惊人的!

我有一个像 txt 文件中的简单表格:

Jorgito 10 1 Soltero
Juanito 20 2 Casado
Jaimito 30 3 Divociado

我编写了一些初步的代码:

var RDD_filas = RDD_datos.map(_.split("\t"))
var esquema = new StructType()
.add("Nombre", StringType)
.add("Edad", IntegerType)
.add("Hijos",IntegerType)
.add("EC",StringType)

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

case class X(Nombre: String, Edad: Int, Hijos: Int, EC: String)

然后,我应用我见过的所有不起作用的方法:

var DF_datos = RDD_filas.map({case Array(s0, s1, s2, s3) => X(s0, s1.trim.toInt, s2.trim.toInt, s3)}).toDF("Nombre","Edad","Hijos","EC")
var DF_datos2 = RDD_filas.map(p => X(p(0), p(1).trim.toInt,p(2).trim.toInt,p(3))).toDF("Nombre","Edad","Hijos","EC")
var DF_datos3 = RDD_filas.map(Array(s0, s1, s2, s3) => Array(s0, s1.trim.toInt, s2.trim.toInt, s3)).toDF("Nombre","Edad","Hijos","EC")
var DF_datos4 = sqlContext.createDataFrame(RDD_filas,esquema)

前三种方法允许我创建 DF 并打印它们的模式,但它们没有 header(DF_datos.header() 返回第一行),如果我尝试 DF_datos.show() 我会出错最奇怪的一个(对我来说)是数字 4,因为它应该是最“规范”的方式。

只有这对我有用:

var a = RDD_datos.map(_.split(" ")).take(3)
val rdd = sc.makeRDD(a)
val df = rdd.map {case Array(s0, s1, s2, s3) => X(s0, s1.toInt, s2.toInt, s3)}.toDF()

为了使用sqlContext.createDataFrame您将需要具有RDD[Row] ,其中RDD[Row]中条目的类型与架构中的类型相对应。 因此,您将需要在适当的时候将某些条目从String转换为Int

这是一个例子:

scala> val data = sc.textFile("./junk/dat.txt")
data: org.apache.spark.rdd.RDD[String] = ./junk/dat.txt MapPartitionsRDD[20] at textFile at <console>:28

scala> data.foreach{println}
Jorgito 10 1 Soltero
Juanito 20 2 Casado
Jaimito 30 3 Divociado

scala> :pa
// Entering paste mode (ctrl-D to finish)

var esquema = new StructType()
.add("Nombre", StringType)
.add("Edad", IntegerType)
.add("Hijos",IntegerType)
.add("EC",StringType)

// Exiting paste mode, now interpreting.

esquema: org.apache.spark.sql.types.StructType = StructType(StructField(Nombre,StringType,true), StructField(Edad,IntegerType,true), StructField(Hijos,IntegerType,true), StructField(EC,StringType,true))

scala> val rowRDD = data.map(l => l.split(" ")).map{case Array(a,b,c,d) => Row(a, b.toInt, c.toInt, d)}
rowRDD: org.apache.spark.rdd.RDD[org.apache.spark.sql.Row] = MapPartitionsRDD[22] at map at <console>:30

scala> val df = sqlContext.createDataFrame(rowRDD, esquema)
df: org.apache.spark.sql.DataFrame = [Nombre: string, Edad: int ... 2 more fields]

scala> df.show
+-------+----+-----+---------+
| Nombre|Edad|Hijos|       EC|
+-------+----+-----+---------+
|Jorgito|  10|    1|  Soltero|
|Juanito|  20|    2|   Casado|
|Jaimito|  30|    3|Divociado|
+-------+----+-----+---------+

但是,这需要大量工作,因此我建议您a)升级到Spark 2.0并使用内置的DataFrameReader csv加载程序,或者b)查看spark-csv 在这两种情况下,您只需根据需要将定界符设置为\\s\\t

一种方法是使用 Struct Type 将列标题添加到 csv

val df = spark.createDataFrame(rdd, structType)  

如果 csv 已经包含列标题,则可以直接将其转换为 Data frame。

val df = spark.read.option("headers",true).csv("/path/to/csv")

从源文件转换为 DataFrame

现在您已经使用了自定义定界符

val df = spark.read.option("delimiter", " ").csv("/path/to/csv")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM