将PostgreSQL数据库加载到SchemaRDD

时间:2014-12-28 06:01:27

标签: postgresql scala apache-spark apache-spark-sql

我在PostgreSQL中有数百万行和100多列的数据源,我想使用Spark SQL,所以我想将这个数据源转换为SchemaRDD

Spark SQL Programming Guide中引入了两种方法,  一个是通过反思,这意味着我需要定义:

case class Row(Var1: Int, Var2: String, ...)

这很乏味,因为我有100多列。

另一种方法是“以编程方式指定架构”,这意味着我需要定义:

val schema =
  StructType(
    Seq(StructField("Var1", IntegerType), StructField("Var2", StringType), ...))

这对我来说也很乏味。

实际上,还有另一个问题,因为我使用PostgreSQL类加载了JdbcRDD数据库,但我发现我还需要在mapRow JdbcRDD参数中定义模式构造函数,看起来像:

def extractValues(r: ResultSet) = {
  (r.getInt("Var1"), r.getString("Var2"), ...)
}
val dbRDD = new JdbcRDD(sc, createConnection,
  "SELECT * FROM PostgreSQL OFFSET ? LIMIT ?",
  0, 1000000, 1, extractValues)

此API仍然要求我自己创建架构,更糟糕的是我需要重做类似的事情来将此JdbcRDD转换为SchemaRDD,这将是非常笨拙的代码。

所以我想知道这项任务的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

您需要支持的数据类型有限。为什么不使用

java.sql.ResultSetMetaData

e.g。

val rs = jdbcStatement.executeQuery("select * from myTable limit 1")
val rmeta = rs.getMetaData

读取一行,然后为每个列动态生成所需的StructField。

您需要一个案例陈述来处理

val myStructFields = for (cx <- 0 until rmeta.getColumnCount) {
       val jdbcType = rmeta.getColumnType(cx)
       } yield StructField(rmeta.getColumnName(cx),jdbcToSparkType(jdbcType))

val mySchema = StructType(myStructFields.toSeq)

其中jdbcToSparkType位于以下行:

  def jdbcToSparkType(jdbcType: Int) = {
    jdbcType match {
       case 4 => InteegerType  
       case 6 => FloatType
        ..
   }  

UPDATE 要生成RDD [Row]:您将遵循类似的模式。在这种情况下,你会

val rows = for (rs.next) {
    row = jdbcToSpark(rs)
    } yield row

val rowRDD = sc.parallelize(rows)

其中

def jdbcToSpark(rs: ResultSet) = {
   var rowSeq = Seq[Any]()
   for (cx <- 0 to rs.getMetaData.getColumnCount) {
     rs.getColumnType(cx) match {
         case 4 => rowSeq :+ rs.getInt(cx)
          ..
     }
   }
   Row.fromSeq(rowSeq)
}

然后     val行