由Spark JDBC读取表头

时间:2017-05-03 12:03:11

标签: scala apache-spark jdbc hive orc

我正在尝试使用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)at at   org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils $$ anonfun $ $组织阿帕奇$火花$ SQL $执行$ $的数据源JDBC $ JdbcUtils $$ makeGetter $ 8.apply(JdbcUtils.scala:365)     在   org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils $$ anonfun $ $组织阿帕奇$火花$ SQL $执行$ $的数据源JDBC $ JdbcUtils $$ makeGetter $ 8.apply(JdbcUtils.scala:364)     在   org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils $$匿名$ 1.getNext(JdbcUtils.scala:286)     在   org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils $$匿名$ 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(未知   来源)at   org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43)     在   org.apache.spark.sql.execution.WholeStageCodegenExec $$ anonfun $ 8 $$不久$ 1.hasNext(WholeStageCodegenExec.scala:377)     在   org.apache.spark.sql.execution.SparkPlan $$ anonfun $ 2.适用(SparkPlan.scala:231)     在   org.apache.spark.sql.execution.SparkPlan $$ anonfun $ 2.适用(SparkPlan.scala:225)     在   org.apache.spark.rdd.RDD $$ anonfun $ mapPartitionsInternal $ 1 $$ anonfun $ $申请25.apply(RDD.scala:826)     在   org.apache.spark.rdd.RDD $$ anonfun $ mapPartitionsInternal $ 1 $$ anonfun $ $申请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)at   org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87)at at   org.apache.spark.scheduler.Task.run(Task.scala:99)at   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)at   java.lang.Long.parseLong(Long.java:631)at   org.apache.hive.jdbc.HiveBaseResultSet.getLong(HiveBaseResultSet.java:368)     ......还有22个

输入字符串" metrics.t"对应于第二列的表名和名称," t",其中包含时间戳。

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

CSV选项("标题",true)对我的情况无效。

PS:Spark版本2.1.0

3 个答案:

答案 0 :(得分: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(),则会再次返回异常。

答案 1 :(得分:1)

我在初始化SparkSession时启用了Hive支持,对我有用:

def Regional_category(self, response):
    names = {'name1':'Regional_subcategories',
             'name2':'Related_Categories',
             'name3':'Site title',
             'name4':'Site Description',
             }
    finder = {'finder1': '.browse-node::text',
              'finder2': '.one-browse-node::text',
              'finder3': '.site-title::text',
              'finder4': '.site-descr::text',
              }
    yield from self.find_items(response, names, finder)

答案 2 :(得分:0)

因为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?