Spark JDBC:DataFrameReader 无法读取数据类型为 ROWID 的 Oracle 表

Posted

技术标签:

【中文标题】Spark JDBC:DataFrameReader 无法读取数据类型为 ROWID 的 Oracle 表【英文标题】:Spark JDBC: DataFrameReader fails to read Oracle table with datatype as ROWID 【发布时间】:2018-09-09 12:21:34 【问题描述】:

我正在尝试使用 spark.read.format 读取 Oracle 表,它适用于所有表,除了少数表具有任何数据类型为 ROWID 的列。

下面是我的代码

var df = spark.read.format("jdbc").
        option("url", url).
        option("driver", driver).
        option("dbtable", dbTable).load()
println(df.first)

我收到以下错误

18/09/08 11:38:17 WARN scheduler.TaskSetManager: Lost task 0.0 in stage 5.0 (TID 23, gbrdsr000002985.intranet.barcapint.com, executor 21): java.sql.SQLException: Invalid column type: getLong not implemented for class oracle.jdbc.driver.T4CRowidAccessor
    at oracle.jdbc.driver.GeneratedAccessor.getLong(GeneratedAccessor.java:440)
    at oracle.jdbc.driver.GeneratedStatement.getLong(GeneratedStatement.java:228)
    at oracle.jdbc.driver.GeneratedScrollableResultSet.getLong(GeneratedScrollableResultSet.java:620)
    at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$org$apache$spark$sql$execution$datasources$jdbc$JdbcUtils$$makeGetter$8.apply(JdbcUtils.scala:365)
    at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$org$apache$spark$sql$execution$datasources$jdbc$JdbcUtils$$makeGetter$8.apply(JdbcUtils.scala:364)

分析:我检查了JdbcUtils对象,发现案例java.sql.Types.ROWID映射到spark的LongType。但是在 Oracle JDBC 驱动程序中没有为 ROWID 类型实现 getLong。 我相信如果我设法将它映射到 StringType 那么它将起作用,但我找不到任何解决方法。请在此处提出解决方案。

到目前为止,我正在使用 ResultSet 读取数据,然后使用自定义模式将其转换为 DataFrame,但它会破坏并行性。还想检查是否有任何选项来修改 JdbcUtils 的代码,因为我无法扩展 DataFrameReader 以创建自定义的,因为在类定义中提到了“private [sql]”。

【问题讨论】:

我使用的是 Spark 2.1.0,但最新的 JdbcUtils 具有相同的映射。 你为什么想要ROWID? @thebluephantom 好问题!实际上整个表都发布到一个文件中,我需要验证它。它不是一个伪列,它是一个 ROWID 类型的实际列 我曾经是 ORACLE DBA,有点意思。我第一次听说这个。 如何定义一个view 来重新定义列类型? 【参考方案1】:
val df=spark.read
  .format("jdbc")
  .option("driver","oracle.jdbc.OracleDriver")
  .option("url","jdbc:oracle:thin:@localhost:1521:orcl")
  .option("user","oracle1")
  .option("password","oracle1")
  .option("dbtable","(select Cast(RID as VARCHAR2(18)) from sample.ALL_RESULTS_DATA)  my_table")
  .load()

RID 是 oracle 中数据类型为 ROWID 的列名。

上面的代码会将ROWID数据类型转换为String,以便我们可以使用Spark读取它

结果:

-------------------------+
|CAST(RIDASVARCHAR2(18))AS|
+-------------------------+
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|
|       AAAIVuAABAAAMhCAAA|

【讨论】:

以上是关于Spark JDBC:DataFrameReader 无法读取数据类型为 ROWID 的 Oracle 表的主要内容,如果未能解决你的问题,请参考以下文章

spark - jdbc升级版数据源

将 jdbc 连接传递给 spark 读取

通过 Spark 的 Hive JDBC 连接(Nullpointer 异常)

Spark JDBC 中的伪列

其他让 spark 分区读取 jdbc 的方法

Spark Jdbc 连接 JDBCOptions