我在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
,这将是非常笨拙的代码。
所以我想知道这项任务的最佳方法是什么?
答案 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行