it-swarm.com.de

Wie konvertiert man ein rdd Objekt in einen Datenrahmen in spark

Wie kann ich ein RDD (org.Apache.spark.rdd.RDD[org.Apache.spark.sql.Row]) in ein Dataframe org.Apache.spark.sql.DataFrame konvertieren? Ich habe einen Datenrahmen mit .rdd nach rdd konvertiert. Nach der Verarbeitung möchte ich es wieder in Datenrahmen. Wie kann ich das machen ?

122
user568109

SqlContext verfügt über eine Reihe von createDataFrame-Methoden, die eine DataFrame mit einer RDD erstellen. Ich kann mir vorstellen, dass eine davon für Ihren Kontext geeignet ist.

Zum Beispiel:

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

Erstellt einen DataFrame aus einer RDD mit Zeilen unter Verwendung des angegebenen Schemas.

83

Dieser Code funktioniert perfekt ab Spark 2.x mit Scala 2.11

Importieren Sie die erforderlichen Klassen

import org.Apache.spark.sql.{Row, SparkSession}
import org.Apache.spark.sql.types.{DoubleType, StringType, StructField, StructType}

Erstelle SparkSession Objekt, hier ist es spark

val spark: SparkSession = SparkSession.builder.master("local").getOrCreate
val sc = spark.sparkContext // Just used to create test RDDs

Lassen Sie uns ein RDD machen es 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))
  )
)

Methode 1

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

Methode 2

Verwenden Sie SparkSession.createDataFrame(RDD obj) und geben Sie die Spaltennamen an.

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

Methode 3 (Aktuelle Antwort auf Frage)

Auf diese Weise muss die Eingabe rdd vom Typ RDD[Row] sein.

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

erstellen Sie das Schema

val schema = new StructType()
  .add(StructField("id", StringType, true))
  .add(StructField("val1", DoubleType, true))
  .add(StructField("val2", DoubleType, true))

Wenden Sie nun sowohl rowsRdd als auch schema auf createDataFrame() an

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

Angenommen, Ihre RDD [Zeile] heißt rdd, können Sie Folgendes verwenden:

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

Hinweis: Diese Antwort wurde ursprünglich veröffentlicht hier

Ich poste diese Antwort, weil ich zusätzliche Details zu den verfügbaren Optionen mitteilen möchte, die ich in den anderen Antworten nicht gefunden habe


Um einen DataFrame aus einem RDD von Zeilen zu erstellen, gibt es zwei Hauptoptionen:

1) Wie bereits erwähnt, können Sie toDF() verwenden, das mit import sqlContext.implicits._ importiert werden kann. Dieser Ansatz funktioniert jedoch nur für die folgenden RDD-Typen:

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

(Quelle: Scaladoc des Objekts SQLContext.implicits)

Die letzte Signatur bedeutet tatsächlich, dass sie für eine RDD von Tupeln oder eine RDD von Fallklassen funktionieren kann (da Tupel und Fallklassen Unterklassen von scala.Product sind).

Um diesen Ansatz für einen RDD[Row] zu verwenden, müssen Sie ihn einem RDD[T <: scala.Product] zuordnen. Dies kann erreicht werden, indem jede Zeile einer benutzerdefinierten Fallklasse oder einem Tupel zugeordnet wird, wie in den folgenden Codefragmenten dargestellt:

val df = rdd.map({ 
  case Row(val1: String, ..., valN: Long) => (val1, ..., valN)
}).toDF("col1_name", ..., "colN_name")

oder

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

Der Hauptnachteil dieses Ansatzes ist (meiner Meinung nach), dass Sie das Schema des resultierenden DataFrames in der Kartenfunktion Spalte für Spalte explizit festlegen müssen. Möglicherweise kann dies programmgesteuert erfolgen, wenn Sie das Schema nicht im Voraus kennen, aber es kann dort etwas chaotisch werden. Es gibt also alternativ eine andere Option:


2) Sie können createDataFrame(rowRDD: RDD[Row], schema: StructType) wie in der akzeptierten Antwort verwenden, die im Objekt SQLContext verfügbar ist. Beispiel für die Konvertierung eines RDD eines alten DataFrame:

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

Beachten Sie, dass keine Schemaspalte explizit festgelegt werden muss. Wir verwenden das alte DF-Schema, das der Klasse StructType angehört und problemlos erweitert werden kann. Dieser Ansatz ist jedoch manchmal nicht möglich und in einigen Fällen weniger effizient als der erste.

17
Daniel de Paula

Angenommen, Sie haben ein DataFrame und möchten einige Änderungen an den Felddaten vornehmen, indem Sie sie in RDD[Row] konvertieren.

val aRdd = aDF.map(x=>Row(x.getAs[Long]("id"),x.getAs[List[String]]("role").head))

Um von DataFrame zurück zu RDD zu konvertieren, müssen wir das Strukturtyp des RDD definieren.

Wenn der Datentyp Long war, wird er in der Struktur LongType.

Wenn String, dann StringType in der Struktur.

val aStruct = new StructType(Array(StructField("id",LongType,nullable = true),StructField("role",StringType,nullable = true)))

Jetzt können Sie die RDD mit der Methode createDataFrame in DataFrame konvertieren.

val aNamedDF = sqlContext.createDataFrame(aRdd,aStruct)
15
Ajay Gupta

Hier ist ein einfaches Beispiel für die Konvertierung Ihrer Liste in Spark RDD und die anschließende Konvertierung dieser Spark RDD in Dataframe.

Bitte beachten Sie, dass ich Spark-Shells scalaREPL verwendet habe, um folgenden Code auszuführen. Hier ist sc eine Instanz von SparkContext, die implizit in Spark-Shell verfügbar ist. Hoffe es beantwortet deine Frage.

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

Methode 1: (Scala)

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

Methode 2: (Scala)

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

Methode 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()

Methode 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()

Extrahierte den Wert aus dem Zeilenobjekt und wandte dann die case-Klasse an, um rdd in DF zu konvertieren

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

Auf neueren Versionen von 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: _*)
3
ozzieisaacs
One needs to create a schema, and attach it to the Rdd.

Angenommen, val spark ist ein Produkt eines 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 

Gleiche Schritte, jedoch mit weniger val-Deklarationen:

    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
teserecter

Um ein Array [Row] in DataFrame oder Dataset zu konvertieren, funktioniert Folgendes elegant:

Angenommen, Schema ist dann der StructType für die Zeile

val rows: Array[Row]=...
implicit val encoder = RowEncoder.apply(schema)
import spark.implicits._
rows.toDS
0
Tom