How to convert spark SchemaRDD into RDD of my case class?

后端 未结 4 1724
长发绾君心
长发绾君心 2020-12-25 08:04

In the spark docs it\'s clear how to create parquet files from RDD of your own case classes; (from the docs)



        
4条回答
  •  清酒与你
    2020-12-25 09:03

    The best solution I've come up with that requires the least amount of copy and pasting for new classes is as follows (I'd still like to see another solution though)

    First you have to define your case class, and a (partially) reusable factory method

    import org.apache.spark.sql.catalyst.expressions
    
    case class MyClass(fooBar: Long, fred: Long)
    
    // Here you want to auto gen these functions using macros or something
    object Factories extends java.io.Serializable {
      def longLong[T](fac: (Long, Long) => T)(row: expressions.Row): T = 
        fac(row(0).asInstanceOf[Long], row(1).asInstanceOf[Long])
    }
    

    Some boiler plate which will already be available

    import scala.reflect.runtime.universe._
    val sqlContext = new org.apache.spark.sql.SQLContext(sc)
    import sqlContext.createSchemaRDD
    

    The magic

    import scala.reflect.ClassTag
    import org.apache.spark.sql.SchemaRDD
    
    def camelToUnderscores(name: String) = 
      "[A-Z]".r.replaceAllIn(name, "_" + _.group(0).toLowerCase())
    
    def getCaseMethods[T: TypeTag]: List[String] = typeOf[T].members.sorted.collect {
      case m: MethodSymbol if m.isCaseAccessor => m
    }.toList.map(_.toString)
    
    def caseClassToSQLCols[T: TypeTag]: List[String] = 
      getCaseMethods[T].map(_.split(" ")(1)).map(camelToUnderscores)
    
    def schemaRDDToRDD[T: TypeTag: ClassTag](schemaRDD: SchemaRDD, fac: expressions.Row => T) = {
      val tmpName = "tmpTableName" // Maybe should use a random string
      schemaRDD.registerAsTable(tmpName)
      sqlContext.sql("SELECT " + caseClassToSQLCols[T].mkString(", ") + " FROM " + tmpName)
      .map(fac)
    }
    

    Example use

    val parquetFile = sqlContext.parquetFile(path)
    
    val normalRDD: RDD[MyClass] = 
      schemaRDDToRDD[MyClass](parquetFile, Factories.longLong[MyClass](MyClass.apply))
    

    See also:

    http://apache-spark-user-list.1001560.n3.nabble.com/Spark-SQL-Convert-SchemaRDD-back-to-RDD-td9071.html

    Though I failed to find any example or documentation by following the JIRA link.

提交回复
热议问题