ฉันจะแปลง RDD ( org.apache.spark.rdd.RDD[org.apache.spark.sql.Row]
) เป็น Dataframe org.apache.spark.sql.DataFrame
ได้อย่างไร ผมแปลง dataframe เพื่อ RDD .rdd
ใช้ หลังจากการประมวลผลฉันต้องการมันกลับมาใน dataframe ฉันจะทำสิ่งนี้ได้อย่างไร
ฉันจะแปลง RDD ( org.apache.spark.rdd.RDD[org.apache.spark.sql.Row]
) เป็น Dataframe org.apache.spark.sql.DataFrame
ได้อย่างไร ผมแปลง dataframe เพื่อ RDD .rdd
ใช้ หลังจากการประมวลผลฉันต้องการมันกลับมาใน dataframe ฉันจะทำสิ่งนี้ได้อย่างไร
คำตอบ:
SqlContext
มีจำนวนของcreateDataFrame
วิธีการที่สร้างDataFrame
รับ RDD
ฉันคิดว่าหนึ่งในสิ่งเหล่านี้จะได้ผลกับบริบทของคุณ
ตัวอย่างเช่น:
def createDataFrame(rowRDD: RDD[Row], schema: StructType): DataFrame
สร้าง DataFrame จาก RDD ที่มีแถวโดยใช้สคีมาที่กำหนด
รหัสนี้ทำงานได้อย่างสมบูรณ์แบบจาก Spark 2.x กับ Scala 2.11
นำเข้าคลาสที่จำเป็น
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.types.{DoubleType, StringType, StructField, StructType}
สร้างSparkSession
วัตถุและนี่คือมันspark
val spark: SparkSession = SparkSession.builder.master("local").getOrCreate
val sc = spark.sparkContext // Just used to create test RDDs
เรามาRDD
สร้างมันกันเถอะDataFrame
val rdd = sc.parallelize(
Seq(
("first", Array(2.0, 1.0, 2.1, 5.4)),
("test", Array(1.5, 0.5, 0.9, 3.7)),
("choose", Array(8.0, 2.9, 9.1, 2.5))
)
)
SparkSession.createDataFrame(RDD obj)
การใช้
val dfWithoutSchema = spark.createDataFrame(rdd)
dfWithoutSchema.show()
+------+--------------------+
| _1| _2|
+------+--------------------+
| first|[2.0, 1.0, 2.1, 5.4]|
| test|[1.5, 0.5, 0.9, 3.7]|
|choose|[8.0, 2.9, 9.1, 2.5]|
+------+--------------------+
การใช้SparkSession.createDataFrame(RDD obj)
และการระบุชื่อคอลัมน์
val dfWithSchema = spark.createDataFrame(rdd).toDF("id", "vals")
dfWithSchema.show()
+------+--------------------+
| id| vals|
+------+--------------------+
| first|[2.0, 1.0, 2.1, 5.4]|
| test|[1.5, 0.5, 0.9, 3.7]|
|choose|[8.0, 2.9, 9.1, 2.5]|
+------+--------------------+
วิธีนี้ต้องใช้การป้อนข้อมูลที่ควรจะเป็นประเภทrdd
RDD[Row]
val rowsRdd: RDD[Row] = sc.parallelize(
Seq(
Row("first", 2.0, 7.0),
Row("second", 3.5, 2.5),
Row("third", 7.0, 5.9)
)
)
สร้างสคีมา
val schema = new StructType()
.add(StructField("id", StringType, true))
.add(StructField("val1", DoubleType, true))
.add(StructField("val2", DoubleType, true))
ตอนนี้ใช้ทั้งสองrowsRdd
และschema
การcreateDataFrame()
val df = spark.createDataFrame(rowsRdd, schema)
df.show()
+------+----+----+
| id|val1|val2|
+------+----+----+
| first| 2.0| 7.0|
|second| 3.5| 2.5|
| third| 7.0| 5.9|
+------+----+----+
สมมติว่า RDD ของคุณ [แถว] เรียกว่า rdd คุณสามารถใช้:
val sqlContext = new SQLContext(sc)
import sqlContext.implicits._
rdd.toDF()
หมายเหตุ: คำตอบนี้ถูกโพสต์ที่นี่เดิม
ฉันโพสต์คำตอบนี้เพราะฉันต้องการแบ่งปันรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกที่มีอยู่ซึ่งฉันไม่พบในคำตอบอื่น ๆ
ในการสร้าง DataFrame จาก RDD of Rows มีสองตัวเลือกหลัก:
1)เป็นแหลมออกแล้วคุณสามารถใช้ซึ่งสามารถนำเข้าโดยtoDF()
import sqlContext.implicits._
อย่างไรก็ตามวิธีนี้ใช้ได้กับ RDD ประเภทต่อไปนี้เท่านั้น:
RDD[Int]
RDD[Long]
RDD[String]
RDD[T <: scala.Product]
(ที่มา: ScaladocของSQLContext.implicits
วัตถุ)
ลายเซ็นสุดท้ายจริง ๆ แล้วหมายความว่ามันสามารถทำงานกับ RDD ของ tuples หรือ RDD ของคลาสเคส (เนื่องจาก tuples และคลาสเคสเป็นคลาสย่อยของscala.Product
)
ดังนั้นเพื่อที่จะใช้วิธีการนี้สำหรับคุณต้องแผนที่ไปยังRDD[Row]
RDD[T <: scala.Product]
สิ่งนี้สามารถทำได้โดยการแม็พแต่ละแถวกับคลาสเคสที่กำหนดเองหรือกับ tuple ดังในตัวอย่างโค้ดต่อไปนี้:
val df = rdd.map({
case Row(val1: String, ..., valN: Long) => (val1, ..., valN)
}).toDF("col1_name", ..., "colN_name")
หรือ
case class MyClass(val1: String, ..., valN: Long = 0L)
val df = rdd.map({
case Row(val1: String, ..., valN: Long) => MyClass(val1, ..., valN)
}).toDF("col1_name", ..., "colN_name")
ข้อเสียเปรียบหลักของวิธีการนี้ (ในความคิดของฉัน) คือคุณต้องกำหนดสคีมาของ DataFrame ผลลัพธ์ในฟังก์ชันแผนที่โดยเรียงตามคอลัมน์ บางทีนี่อาจทำได้โดยทางโปรแกรมหากคุณไม่ทราบสคีล่วงหน้า แต่สิ่งต่าง ๆ อาจยุ่งเหยิงไปเล็กน้อย ดังนั้นอีกทางเลือกหนึ่งคือ:
2)คุณสามารถใช้createDataFrame(rowRDD: RDD[Row], schema: StructType)
ในคำตอบที่ยอมรับได้ซึ่งมีอยู่ในวัตถุSQLContext ตัวอย่างสำหรับการแปลง RDD ของ DataFrame เก่า:
val rdd = oldDF.rdd
val newDF = oldDF.sqlContext.createDataFrame(rdd, oldDF.schema)
โปรดทราบว่าไม่จำเป็นต้องตั้งค่าคอลัมน์สคีมาใด ๆ อย่างชัดเจน เราใช้สคีมาของ DF เก่าอีกครั้งซึ่งเป็นStructType
คลาสและสามารถขยายได้อย่างง่ายดาย อย่างไรก็ตามวิธีนี้บางครั้งก็เป็นไปไม่ได้และในบางกรณีอาจมีประสิทธิภาพน้อยกว่าวิธีแรก
import sqlContext.implicits.
สมมติว่าคุณมีและคุณต้องการที่จะทำบางอย่างเกี่ยวกับการปรับเปลี่ยนเขตข้อมูลโดยการแปลงไปDataFrame
RDD[Row]
val aRdd = aDF.map(x=>Row(x.getAs[Long]("id"),x.getAs[List[String]]("role").head))
การแปลงกลับไปDataFrame
จากRDD
ที่เราจำเป็นต้องกำหนดประเภทโครงสร้างRDD
ของ
ถ้าประเภทข้อมูลLong
นั้นมันจะกลายเป็นLongType
ในโครงสร้าง
หากString
แล้วStringType
ในโครงสร้าง
val aStruct = new StructType(Array(StructField("id",LongType,nullable = true),StructField("role",StringType,nullable = true)))
ตอนนี้คุณสามารถแปลง RDD เป็น DataFrame โดยใช้เมธอดcreateDataFrame
val aNamedDF = sqlContext.createDataFrame(aRdd,aStruct)
นี่คือตัวอย่างง่ายๆของการแปลงรายการของคุณเป็น Spark RDD แล้วแปลง Spark RDD นั้นเป็น Dataframe
โปรดทราบว่าฉันได้ใช้ REPL ของ scala-shell เพื่อรันโค้ดต่อไปนี้ Here sc เป็นตัวอย่างของ SparkContext ซึ่งมีอยู่โดยนัยใน Spark-shell หวังว่ามันจะตอบคำถามของคุณ
scala> val numList = List(1,2,3,4,5)
numList: List[Int] = List(1, 2, 3, 4, 5)
scala> val numRDD = sc.parallelize(numList)
numRDD: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[80] at parallelize at <console>:28
scala> val numDF = numRDD.toDF
numDF: org.apache.spark.sql.DataFrame = [_1: int]
scala> numDF.show
+---+
| _1|
+---+
| 1|
| 2|
| 3|
| 4|
| 5|
+---+
วิธีที่ 1: (สกาล่า)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
import sqlContext.implicits._
val df_2 = sc.parallelize(Seq((1L, 3.0, "a"), (2L, -1.0, "b"), (3L, 0.0, "c"))).toDF("x", "y", "z")
วิธีที่ 2: (สกาล่า)
case class temp(val1: String,val3 : Double)
val rdd = sc.parallelize(Seq(
Row("foo", 0.5), Row("bar", 0.0)
))
val rows = rdd.map({case Row(val1:String,val3:Double) => temp(val1,val3)}).toDF()
rows.show()
วิธีที่ 1: (Python)
from pyspark.sql import Row
l = [('Alice',2)]
Person = Row('name','age')
rdd = sc.parallelize(l)
person = rdd.map(lambda r:Person(*r))
df2 = sqlContext.createDataFrame(person)
df2.show()
วิธีที่ 2: (Python)
from pyspark.sql.types import *
l = [('Alice',2)]
rdd = sc.parallelize(l)
schema = StructType([StructField ("name" , StringType(), True) ,
StructField("age" , IntegerType(), True)])
df3 = sqlContext.createDataFrame(rdd, schema)
df3.show()
แยกค่าจากอ็อบเจ็กต์แถวจากนั้นใช้คลาสเคสเพื่อแปลง rdd เป็น DF
val temp1 = attrib1.map{case Row ( key: Int ) => s"$key" }
val temp2 = attrib2.map{case Row ( key: Int) => s"$key" }
case class RLT (id: String, attrib_1 : String, attrib_2 : String)
import hiveContext.implicits._
val df = result.map{ s => RLT(s(0),s(1),s(2)) }.toDF
บน spark รุ่นที่ใหม่กว่า (2.0+)
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._
import org.apache.spark.sql._
import org.apache.spark.sql.types._
val spark = SparkSession
.builder()
.getOrCreate()
import spark.implicits._
val dfSchema = Seq("col1", "col2", "col3")
rdd.toDF(dfSchema: _*)
One needs to create a schema, and attach it to the Rdd.
สมมติว่า val spark เป็นผลิตภัณฑ์ของ SparkSession.builder ...
import org.apache.spark._
import org.apache.spark.sql._
import org.apache.spark.sql.types._
/* Lets gin up some sample data:
* As RDD's and dataframes can have columns of differing types, lets make our
* sample data a three wide, two tall, rectangle of mixed types.
* A column of Strings, a column of Longs, and a column of Doubules
*/
val arrayOfArrayOfAnys = Array.ofDim[Any](2,3)
arrayOfArrayOfAnys(0)(0)="aString"
arrayOfArrayOfAnys(0)(1)=0L
arrayOfArrayOfAnys(0)(2)=3.14159
arrayOfArrayOfAnys(1)(0)="bString"
arrayOfArrayOfAnys(1)(1)=9876543210L
arrayOfArrayOfAnys(1)(2)=2.71828
/* The way to convert an anything which looks rectangular,
* (Array[Array[String]] or Array[Array[Any]] or Array[Row], ... ) into an RDD is to
* throw it into sparkContext.parallelize.
* http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.SparkContext shows
* the parallelize definition as
* def parallelize[T](seq: Seq[T], numSlices: Int = defaultParallelism)
* so in our case our ArrayOfArrayOfAnys is treated as a sequence of ArraysOfAnys.
* Will leave the numSlices as the defaultParallelism, as I have no particular cause to change it.
*/
val rddOfArrayOfArrayOfAnys=spark.sparkContext.parallelize(arrayOfArrayOfAnys)
/* We'll be using the sqlContext.createDataFrame to add a schema our RDD.
* The RDD which goes into createDataFrame is an RDD[Row] which is not what we happen to have.
* To convert anything one tall and several wide into a Row, one can use Row.fromSeq(thatThing.toSeq)
* As we have an RDD[somethingWeDontWant], we can map each of the RDD rows into the desired Row type.
*/
val rddOfRows=rddOfArrayOfArrayOfAnys.map(f=>
Row.fromSeq(f.toSeq)
)
/* Now to construct our schema. This needs to be a StructType of 1 StructField per column in our dataframe.
* https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.types.StructField shows the definition as
* case class StructField(name: String, dataType: DataType, nullable: Boolean = true, metadata: Metadata = Metadata.empty)
* Will leave the two default values in place for each of the columns:
* nullability as true,
* metadata as an empty Map[String,Any]
*
*/
val schema = StructType(
StructField("colOfStrings", StringType) ::
StructField("colOfLongs" , LongType ) ::
StructField("colOfDoubles", DoubleType) ::
Nil
)
val df=spark.sqlContext.createDataFrame(rddOfRows,schema)
/*
* +------------+----------+------------+
* |colOfStrings|colOfLongs|colOfDoubles|
* +------------+----------+------------+
* | aString| 0| 3.14159|
* | bString|9876543210| 2.71828|
* +------------+----------+------------+
*/
df.show
ขั้นตอนเดียวกัน แต่มีการประกาศ val น้อยลง:
val arrayOfArrayOfAnys=Array(
Array("aString",0L ,3.14159),
Array("bString",9876543210L,2.71828)
)
val rddOfRows=spark.sparkContext.parallelize(arrayOfArrayOfAnys).map(f=>Row.fromSeq(f.toSeq))
/* If one knows the datatypes, for instance from JDBC queries as to RDBC column metadata:
* Consider constructing the schema from an Array[StructField]. This would allow looping over
* the columns, with a match statement applying the appropriate sql datatypes as the second
* StructField arguments.
*/
val sf=new Array[StructField](3)
sf(0)=StructField("colOfStrings",StringType)
sf(1)=StructField("colOfLongs" ,LongType )
sf(2)=StructField("colOfDoubles",DoubleType)
val df=spark.sqlContext.createDataFrame(rddOfRows,StructType(sf.toList))
df.show
ฉันพยายามที่จะอธิบายถึงวิธีการแก้ปัญหาโดยใช้ปัญหาการนับจำนวนคำ 1. อ่านไฟล์โดยใช้ sc
วิธีการสร้าง DF
val rdd=sc.textFile("D://cca175/data/")
val df = sc.textFile ("D: // cca175 / data /") .toDF ("t1") df.show
val df=rdd.flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>(x+y)).toDF("word","count")
val df=spark.createDataFrame(wordRdd)
# with header
val df=spark.createDataFrame(wordRdd).toDF("word","count") df.show
นำเข้า org.apache.spark.sql.types._
val schema = โครงสร้างใหม่ () เพิ่ม (StructField ( "คำว่า" StringType จริง)) เพิ่ม (StructField ( "นับ" StringType จริง))
import org.apache.spark.sql.Row
val rowRdd=wordRdd.map(x=>(Row(x._1,x._2)))
val df = spark.createDataFrame (rowRdd, schema)
df.show
ในการแปลง Array [Row] เป็น DataFrame หรือชุดข้อมูลต่อไปนี้จะทำงานได้อย่างสวยงาม:
สมมติว่า schema เป็น StructType สำหรับแถวนั้น
val rows: Array[Row]=...
implicit val encoder = RowEncoder.apply(schema)
import spark.implicits._
rows.toDS