【问题标题】:java.lang.NumberFormatException caused by Spark JDBC reading table headerSpark JDBC读取表头引起的java.lang.NumberFormatException
【发布时间】:2017-10-01 06:07:11
【问题描述】:

我正在尝试使用 Spark 的 JDBC 访问存储在远程集群上的表(ORC 格式):

val jdbcDF = spark.read
      .format("jdbc")
      .option("url", url)
      .option("dbtable", "metrics")
      .option("user", user)
      .option("password", password)
      .load()

但是,无论我做什么,我都会不断收到此错误:

原因:java.sql.SQLException:无法将第 2 列转换为 long: java.lang.NumberFormatException:对于输入字符串:“metrics.t” at org.apache.hive.jdbc.HiveBaseResultSet.getLong(HiveBaseResultSet.java:372) 在 org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$org$apache$spark$sql$execution$datasources$jdbc$JdbcUtils$$makeGetter$8.apply(JdbcUtils.scala:365) 在 org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$org$apache$spark$sql$execution$datasources$jdbc$JdbcUtils$$makeGetter$8.apply(JdbcUtils.scala:364) 在 org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anon$1.getNext(JdbcUtils.scala:286) 在 org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anon$1.getNext(JdbcUtils.scala:268) 在 org.apache.spark.util.NextIterator.hasNext(NextIterator.scala:73) 在 org.apache.spark.util.CompletionIterator.hasNext(CompletionIterator.scala:32) 在 org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIterator.processNext(未知 来源)在 org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43) 在 org.apache.spark.sql.execution.WholeStageCodegenExec$$anonfun$8$$anon$1.hasNext(WholeStageCodegenExec.scala:377) 在 org.apache.spark.sql.execution.SparkPlan$$anonfun$2.apply(SparkPlan.scala:231) 在 org.apache.spark.sql.execution.SparkPlan$$anonfun$2.apply(SparkPlan.scala:225) 在 org.apache.spark.rdd.RDD$$anonfun$mapPartitionsInternal$1$$anonfun$apply$25.apply(RDD.scala:826) 在 org.apache.spark.rdd.RDD$$anonfun$mapPartitionsInternal$1$$anonfun$apply$25.apply(RDD.scala:826) 在 org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38) 在 org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323) 在 org.apache.spark.rdd.RDD.iterator(RDD.scala:287) 在 org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87) 在 org.apache.spark.scheduler.Task.run(Task.scala:99) 在 org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:282) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 在 java.lang.Thread.run(Thread.java:745) 原因: java.lang.NumberFormatException:对于输入字符串:“metrics.t” at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) 在 java.lang.Long.parseLong(Long.java:589) 在 java.lang.Long.parseLong(Long.java:631) 在 org.apache.hive.jdbc.HiveBaseResultSet.getLong(HiveBaseResultSet.java:368) ... 22 更多

输入字符串“metrics.t”对应于表名和第二列的名称,“t”,其特征在于时间戳。

如何跳过带有 JDBC 格式的标头?

CSV 选项 ("header", true) 在我的情况下无效。

PS:Spark 2.1.0 版

【问题讨论】:

  • url 是什么?您是否正在从 Hive 阅读?
  • @JacekLaskowski 是的,我正在从 Hive 阅读。这是网址:val url = "jdbc:hive2://localhost:10000/default"

标签: scala apache-spark jdbc hive orc


【解决方案1】:

以下实现代码不会抛出任何异常:

val jdbcUrl = s"jdbc:hive2://$jdbcHostname:$jdbcPort/$jdbcDatabase"

val connectionProperties = new java.util.Properties()
connectionProperties.setProperty("user", jdbcUsername)
connectionProperties.setProperty("password", jdbcPassword)

val jdbcDF = spark.read.jdbc(jdbcUrl, "metrics", Array(), connectionProperties)

奇怪的是,如果我删除空谓词Array(),异常又回来了。

【讨论】:

  • 您使用的是哪个 JDBC 驱动程序?因为 Apache 驱动程序有很多限制(即没有实现所有预期的 JDBC 功能),并且对 Hadoop 库有繁琐的依赖(尤其是在涉及 Kerberos 时); Cloudera 驱动程序更健壮,适用于 JDBC。当然,如果您的 Spark 构建具有与 Hive 的本机集成,请放弃 JDBC,只需 sqlContext.sql("select * from mydb.mytbl")...
  • @SamsonScharfrichter 确实是 Apache Hive 驱动程序。我将尝试在远程集群上复制我的环境以放弃 JDBC。谢谢。
  • 你不需要在远程集群上运行 Spark 来使用本地 Hive 集成——这只是意味着 Spark 连接到 Metastore 服务(以获取 HDFS 位置给定表的数据文件)然后连接到 HDFS。将相关配置文件从集​​群节点(从/etc/hadoop/conf//etc/hive/conf/)复制到本地目录,然后在spark-env.sh 中设置HADOOP_CONF_DIR(加上 un peu de debugging sinon c'est pas drôle)
【解决方案2】:

因为 Spark JdbcDialect 使用双引号作为 quoteIdentifier 并且它不提供 HiveDialect(不像 MySQL)。

因此,Spark 会通过 JDBC 将这样的 SQL 发送到 Hive:select "some_column_name" from table,而 "some_column_name" 原来是字符串标量而不是列名。

val jdbcDF = spark.read.jdbc(jdbcUrl, "metrics", Array(), connectionProperties) 通过这行代码,你告诉 Spark 生成一个没有任何分区的 JDBC DataFrame。所以没有实际的数据获取 SQL 被发送到 Hive,Spark 只是给你一个空的 DataFrame。

唯一正确的方法是实现对应的方言: How to specify sql dialect when creating spark dataframe from JDBC?

【讨论】:

    【解决方案3】:

    我在初始化 SparkSession 时启用了 Hive 支持,为我工作:

    SparkSession spark = new SparkSession.Builder()
                    .master("local")
                    .appName("test")
                    .enableHiveSupport()
                    .getOrCreate();
    

    【讨论】:

      猜你喜欢
      • 2017-09-17
      • 1970-01-01
      • 1970-01-01
      • 2020-03-08
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 2021-01-31
      相关资源
      最近更新 更多