Spark 2.2 Scala 中的 TRUNCATE 命令删除 SAP HANA 表而不是截断

Posted

技术标签:

【中文标题】Spark 2.2 Scala 中的 TRUNCATE 命令删除 SAP HANA 表而不是截断【英文标题】:TRUNCATE command in Spark 2.2 Scala drops the SAP HANA Table instead of truncating 【发布时间】:2019-09-18 11:16:39 【问题描述】:

我正在尝试截断 SAP HANA 中的表并使用 Spark Scala 将数据插入其中。 然而, 当我运行脚本时,我的 SAP HANA 表被删除(而不是被截断)并且 代码失败,出现以下 JDBC 错误。

按照规定,我正在使用 .mode(SaveMode.Overwrite).option("truncate","true") 来避免删除表,但它没有按照文档中的说明运行。

谁能帮我写代码?

代码:

import spark.implicits._
import org.apache.spark.SparkContext;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.SparkSession;
import org.apache.spark._
import org.apache.hadoop._
import org.apache.hadoop.conf.Configuration
import scala.collection.JavaConverters._
import org.apache.spark.sql.SaveMode
val url = "jdbc:sap://xx.xxx.xx:xx"
val prop = new java.util.Properties
prop.setProperty("driver", "com.sap.db.jdbc.Driver")
prop.setProperty("user", "MYSCHEMA")
prop.setProperty("password", "XXXXX")
val query1 = spark.read.jdbc(url,"MYSCHEMA.PH_SPARK_TRUNCATE",prop)
query1.createOrReplaceTempView("query1_view")
val query1out = spark.sql("select * from query1_view limit 1")
query1out.write.format("jdbc").mode(SaveMode.Overwrite).option("truncate","true")
.option("driver", "com.sap.db.jdbc.Driver")
.option("url", "jdbc:sap://xx.xxx.xx:xx")
.option("dbtable", "MYSCHEMA.PH_SPARK_TRUNCATE")
.option("user", "MYSCHEMA")
.option("password","XXXXX")
.save()

错误:

com.sap.db.jdbc.exceptions.JDBCDriverException: SAP DBTech JDBC: [264] (at 39): invalid datatype: TEXT type is not supported for row table: line 1 col 40 (at pos 39)
  at com.sap.db.jdbc.exceptions.SQLExceptionSapDB._newInstance(SQLExceptionSapDB.java:191)
  at com.sap.db.jdbc.exceptions.SQLExceptionSapDB.newInstance(SQLExceptionSapDB.java:42)
  at com.sap.db.jdbc.packet.HReplyPacket._buildExceptionChain(HReplyPacket.java:973)
  at com.sap.db.jdbc.packet.HReplyPacket.getSQLExceptionChain(HReplyPacket.java:158)
  at com.sap.db.jdbc.packet.HPartInfo.getSQLExceptionChain(HPartInfo.java:40)
  at com.sap.db.jdbc.ConnectionSapDB._receive(ConnectionSapDB.java:3115)
  at com.sap.db.jdbc.ConnectionSapDB.exchange(ConnectionSapDB.java:1518)
  at com.sap.db.jdbc.StatementSapDB._executeDirect(StatementSapDB.java:1419)
  at com.sap.db.jdbc.StatementSapDB._execute(StatementSapDB.java:1398)
  at com.sap.db.jdbc.StatementSapDB._execute(StatementSapDB.java:1383)
  at com.sap.db.jdbc.StatementSapDB._executeUpdate(StatementSapDB.java:1371)
  at com.sap.db.jdbc.StatementSapDB.executeUpdate(StatementSapDB.java:174)
  at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$.createTable(JdbcUtils.scala:805)
  at org.apache.spark.sql.execution.datasources.jdbc.JdbcRelationProvider.createRelation(JdbcRelationProvider.scala:77)
  at org.apache.spark.sql.execution.datasources.DataSource.write(DataSource.scala:471)
  at org.apache.spark.sql.execution.datasources.SaveIntoDataSourceCommand.run(SaveIntoDataSourceCommand.scala:48)
  at org.apache.spark.sql.execution.command.ExecutedCommandExec.sideEffectResult$lzycompute(commands.scala:58)
  at org.apache.spark.sql.execution.command.ExecutedCommandExec.sideEffectResult(commands.scala:56)
  at org.apache.spark.sql.execution.command.ExecutedCommandExec.doExecute(commands.scala:74)
  at org.apache.spark.sql.execution.SparkPlan$$anonfun$execute$1.apply(SparkPlan.scala:117)
  at org.apache.spark.sql.execution.SparkPlan$$anonfun$execute$1.apply(SparkPlan.scala:117)
  at org.apache.spark.sql.execution.SparkPlan$$anonfun$executeQuery$1.apply(SparkPlan.scala:138)
  at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:151)
  at org.apache.spark.sql.execution.SparkPlan.executeQuery(SparkPlan.scala:135)
  at org.apache.spark.sql.execution.SparkPlan.execute(SparkPlan.scala:116)
  at org.apache.spark.sql.execution.QueryExecution.toRdd$lzycompute(QueryExecution.scala:92)
  at org.apache.spark.sql.execution.QueryExecution.toRdd(QueryExecution.scala:92)
  at org.apache.spark.sql.DataFrameWriter.runCommand(DataFrameWriter.scala:609)
  at org.apache.spark.sql.DataFrameWriter.save(DataFrameWriter.scala:233)
  ... 72 elided

【问题讨论】:

【参考方案1】:

错误消息表明应使用数据类型为TEXT 的列创建行存储表。 HANA 不支持。

从堆栈跟踪来看,Spark 似乎正在尝试创建一个表来存储查询执行的结果。我猜它在CREATE TABLE SQL 命令中没有指明表的类型,这意味着HANA 会选择默认表类型。 在 HANA 2 SP04 之前,默认的表类型配置参数是 ROW

由于在大多数情况下这不是最佳选择,因此这里推荐的解决方案是将默认表类型参数更改为COLUMN

我不知道这是否以及如何影响 Spark 关于截断和删除表的行为,但它应该会消除您发布的错误消息。

【讨论】:

谢谢拉尔斯。实际上,我创建了一个仅支持 TEXT 数据类型的列表。我想这里的问题是当我设置 Truncate=True 时,hana 中的表应该被截断。但在我的情况下,spark 正在删除表并重新创建一个行表并尝试将 TEXT 数据放入其中。

以上是关于Spark 2.2 Scala 中的 TRUNCATE 命令删除 SAP HANA 表而不是截断的主要内容,如果未能解决你的问题,请参考以下文章

Spark 2.2 空安全左外连接空指针异常

spark2.2.2安装和集群搭建

Spark/scala 中的 SQL 查询

HikariCP 源码分析之 leakDetectionThreshold 及实战解决 Spark/Scala 连接池泄漏

Spark 作业中的 Scala 成员字段可见性

spark-submit 中的 scala.ScalaReflectionException