स्पर्म में डेटाफ्रेम के लिए आरडीडी ऑब्जेक्ट कैसे कन्वर्ट करें


139

मैं एक RDD ( org.apache.spark.rdd.RDD[org.apache.spark.sql.Row]) को डेटाफ्रेम में कैसे बदल सकता हूं org.apache.spark.sql.DataFrame। मैंने उपयोग करने के लिए एक डेटाफ़्रेम परिवर्तित किया है .rdd। इसे प्रोसेस करने के बाद मैं इसे डेटाफ्रेम में वापस चाहता हूं। मैं यह कैसे कर सकता हूँ ?


जवाबों:


88

SqlContextकई createDataFrameतरीके हैं जो किसी DataFrameदिए गए को बनाते हैं RDD। मुझे लगता है कि इनमें से एक आपके संदर्भ के लिए काम करेगा।

उदाहरण के लिए:

def createDataFrame(rowRDD: RDD[Row], schema: StructType): DataFrame

दिए गए स्कीमा का उपयोग करते हुए एक RDD से एक DataFrame बनाता है।


93

यह कोड स्पार्क 2.x से स्कैला 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))
  )
)

विधि 1

का उपयोग कर 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]|
+------+--------------------+

विधि 2

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]|
+------+--------------------+

विधि 3 (प्रश्न का वास्तविक उत्तर)

इस तरह से इनपुट 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|
+------+----+----+

2
समझने योग्य तरीके से createDataFrame का उपयोग करने के विभिन्न तरीकों को दिखाने के लिए धन्यवाद
vatsug

तीसरी विधि डेटा ईंटों में सहायक है क्योंकि अन्य काम नहीं कर रहे हैं और एक त्रुटि दे रहे हैं
नरेंद्र मारू

67

अपने RDD [पंक्ति] को आरडीडी कहा जाता है, आप उपयोग कर सकते हैं:

val sqlContext = new SQLContext(sc) 
import sqlContext.implicits._
rdd.toDF()

26
मुझे लगता है कि यह RDD [Row] के लिए काम नहीं करता है। क्या मुझे कुछ याद आ रहा है?
डैनियल डे पाउला

4
चूंकि स्पार्क 2.0 SQLContext SparkSession द्वारा प्रतिस्थापित किया जाता है, लेकिन वर्ग को पिछड़े संगतता (स्केलडॉक) के लिए कोड बेस में रखा जाता है इसका उपयोग करते हुए अपक्षय चेतावनी फेंकता है।
टॉमस्केज़ेमाकास

18

नोट: यह उत्तर मूल रूप से यहां पोस्ट किया गया था

मैं इस उत्तर को पोस्ट कर रहा हूं क्योंकि मैं उपलब्ध विकल्पों के बारे में अतिरिक्त विवरण साझा करना चाहूंगा जो मुझे अन्य उत्तरों में नहीं मिला


पंक्तियों के RDD से एक DataFrame बनाने के लिए, दो मुख्य विकल्प हैं:

1) जैसा कि पहले ही बताया गया है, आप इसका उपयोग कर सकते हैं toDF()जिसे आयात किया जा सकता है import sqlContext.implicits._। हालाँकि, यह दृष्टिकोण केवल निम्न प्रकार के RDD के लिए काम करता है:

  • RDD[Int]
  • RDD[Long]
  • RDD[String]
  • RDD[T <: scala.Product]

(स्रोत: वस्तु का मापदण्डSQLContext.implicits )

अंतिम हस्ताक्षर वास्तव में इसका मतलब है कि यह ट्यूपल्स के RDD या केस कक्षाओं के RDD के लिए काम कर सकता है (क्योंकि ट्यूपल्स और केस क्लास उपवर्ग हैं scala.Product)।

इसलिए, ए के लिए इस दृष्टिकोण का उपयोग करने के लिए RDD[Row], आपको इसे मैप करना होगा RDD[T <: scala.Product]। यह प्रत्येक पंक्ति को कस्टम केस क्लास या ट्यूपल पर मैप करके किया जा सकता है, जैसा कि निम्नलिखित कोड स्निपेट में है:

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 ऑब्जेक्ट में उपलब्ध है । पुराने DataFrame का RDD परिवर्तित करने के लिए उदाहरण:

val rdd = oldDF.rdd
val newDF = oldDF.sqlContext.createDataFrame(rdd, oldDF.schema)

ध्यान दें कि किसी स्कीमा कॉलम को स्पष्ट रूप से सेट करने की आवश्यकता नहीं है। हम पुराने डीएफ के स्कीमा का पुन: उपयोग करते हैं, जो StructTypeकक्षा का है और इसे आसानी से बढ़ाया जा सकता है। हालांकि, यह दृष्टिकोण कभी-कभी संभव नहीं होता है, और कुछ मामलों में पहले वाले की तुलना में कम कुशल हो सकता है।


विस्तार के लिए धन्यवादimport sqlContext.implicits.
javadba

भविष्य में, कृपया कई प्रश्नों के समान उत्तर पोस्ट न करें। यदि प्रश्न डुप्लिकेट हैं, तो एक अच्छा उत्तर पोस्ट करें, फिर दूसरे प्रश्न को डुप्लिकेट के रूप में बंद करने के लिए वोट या ध्वज दें। यदि प्रश्न डुप्लिकेट नहीं है, तो प्रश्न के अपने उत्तरों को दर्जी करें। देखिए मैं एक अच्छा उत्तर कैसे लिखूं?

15

मान लीजिए कि आपके पास एक है 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)))

अब आप CreateDataFrame विधि का उपयोग करके RDD को DataFrame में बदल सकते हैं ।

val aNamedDF = sqlContext.createDataFrame(aRdd,aStruct)

7

यहां अपनी सूची को स्पार्क आरडीडी में परिवर्तित करने और फिर उस स्पार्क आरडीडी को डेटाफ्रेम में परिवर्तित करने का एक सरल उदाहरण है।

कृपया ध्यान दें कि मैंने निम्नलिखित कोड को निष्पादित करने के लिए स्पार्क-शेल के स्काला आरईपीएल का उपयोग किया है, यहां एससी स्पार्ककोटेक्स्ट का एक उदाहरण है जो स्पार्क-शेल में निहित है। आशा है कि यह आपके प्रश्न का उत्तर देगा।

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|
+---+

एक मजेदार तथ्य: यह तब काम करना बंद कर देता है, जब आपकी सूची इंट (या लॉन्ग, स्ट्रिंग, <: उत्पाद) के बजाय डबल की होती है।
रिक मोरित्ज़

ओपी का जवाब नहीं देता है: जो
आरडीडी

6

विधि 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: (अजगर)

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: (अजगर)

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

4

स्पार्क के नए संस्करणों पर (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: _*)

1
स्पार्कसेशन sqlContext, hiveContext के लिए सिर्फ एक आवरण है
अर्चित

1
One needs to create a schema, and attach it to the Rdd.

वैल स्पार्क मानकर एक स्पार्कसेशन.बिल्डर का एक उत्पाद है ...

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

मैंने शब्द गणना समस्या का उपयोग करके समाधान को समझाने की कोशिश की । 1. sc का उपयोग कर फ़ाइल पढ़ें

  1. शब्द गणना का निर्माण करें
  2. DF बनाने के तरीके

    • rdd.toDF विधि
    • rdd.toDF ( "शब्द", "गिनती")
      • spark.createDataFrame (RDD, स्कीमा)

    चिंगारी का उपयोग कर फ़ाइल पढ़ें

    val rdd=sc.textFile("D://cca175/data/")  

    Dataframe करने के लिए Rdd

    Val df = sc.textFile ("D: // cca175 / data /") .toDF ("t1") df.show

    विधि 1

    डेटफ्रेम के लिए शब्द संख्या RDD बनाएँ

    val df=rdd.flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>(x+y)).toDF("word","count")

    Method2

    Rdd से डेटाफ़्रेम बनाएँ

    val df=spark.createDataFrame(wordRdd) 
    # with header   
    val df=spark.createDataFrame(wordRdd).toDF("word","count")  df.show

    Method3

    स्कीमों को परिभाषित करें

    आयात org.apache.spark.sql.types._

    वैल स्कीमा = नया स्ट्रक्चर टाइप ()। (StructField ( "शब्द", StringType, true)) जोड़ें। जोड़ने (StructField ( "गिनती", StringType, सच))

    RowRDD बनाएँ

    import org.apache.spark.sql.Row
    val rowRdd=wordRdd.map(x=>(Row(x._1,x._2)))     

    स्कीमा के साथ RDD से DataFrame बनाएं

    वैल df = spark.createDataFrame (rowRdd, स्कीमा)
    df.show


0

एक Array [Row] को DataFrame या Dataset में बदलने के लिए, निम्नलिखित कार्य सुरुचिपूर्ण ढंग से किए जाते हैं:

कहो, स्कीमा पंक्ति के लिए स्ट्रक्चर टाइप है, फिर

val rows: Array[Row]=...
implicit val encoder = RowEncoder.apply(schema)
import spark.implicits._
rows.toDS
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.