Scala 使用sparksql从配置单元表读取数据并写回

Scala 使用sparksql从配置单元表读取数据并写回,scala,hadoop,apache-spark,apache-spark-sql,spark-dataframe,Scala,Hadoop,Apache Spark,Apache Spark Sql,Spark Dataframe,我正在使用Spark SQL读取配置单元表,并将其分配给scala val val x = sqlContext.sql("select * from some_table") 然后我对数据框x进行了一些处理,最后得到了一个数据框y,它具有与表some_table相同的模式 最后,我尝试将y数据帧插入到同一个配置单元表的某个\u表中 y.write.mode(SaveMode.Overwrite).saveAsTable().insertInto("some_table") 然后我得到了错误

我正在使用Spark SQL读取配置单元表,并将其分配给scala val

val x = sqlContext.sql("select * from some_table")
然后我对数据框x进行了一些处理,最后得到了一个数据框y,它具有与表some_table相同的模式

最后,我尝试将y数据帧插入到同一个配置单元表的某个\u表中

y.write.mode(SaveMode.Overwrite).saveAsTable().insertInto("some_table")
然后我得到了错误

org.apache.spark.sql.AnalysisException:无法将覆盖插入也从中读取的表中

我尝试创建一个insert sql语句并使用sqlContext.sql()触发它,但它也给了我同样的错误

有没有办法绕过这个错误?我需要将记录插入到同一个表中


嗨,我试着按照建议去做,但仍然得到同样的错误

val x = sqlContext.sql("select * from incremental.test2")
val y = x.limit(5)
y.registerTempTable("temp_table")
val dy = sqlContext.table("temp_table")
dy.write.mode("overwrite").insertInto("incremental.test2")

scala> dy.write.mode("overwrite").insertInto("incremental.test2")
             org.apache.spark.sql.AnalysisException: Cannot insert overwrite into table that is also being read from.;

您应该首先将数据帧
y
保存在临时表中

y.write.mode("overwrite").saveAsTable("temp_table")
然后可以覆盖目标表中的行

val dy = sqlContext.table("temp_table")
dy.write.mode("overwrite").insertInto("some_table")

实际上,您也可以使用检查点来实现这一点。由于Spark会中断数据沿袭,因此无法检测到您正在读取和覆盖同一个表:

 sqlContext.sparkContext.setCheckpointDir(checkpointDir)
 val ds = sqlContext.sql("select * from some_table").checkpoint()
 ds.write.mode("overwrite").saveAsTable("some_table")

您应该首先将数据框y像拼花地板文件一样保存:

y.write.parquet("temp_table")
加载后,如下所示:

val parquetFile = sqlContext.read.parquet("temp_table")
完成后,在表中插入数据

parquetFile.write.insertInto("some_table")

在Spark 2.2的上下文中

  • 这个错误意味着我们的进程正在从同一个表读取数据,并向同一个表写入数据
  • 通常情况下,这应该在进程写入目录时起作用。hiveStaging
  • saveAsTable方法会发生此错误,因为它会覆盖整个表而不是单个分区
  • insertInto方法不应出现此错误,因为它会覆盖分区而不是表
  • 发生这种情况的一个原因是,配置单元表在其定义中具有以下Spark TBLProperty。如果删除以下Spark TBLProperty,则对于insertInto方法,此问题将得到解决-
  • 'spark.sql.partitionProvider''spark.sql.sources.provider' 'spark.sql.sources.schema.numPartCols 'spark.sql.sources.schema.numParts''spark.sql.sources.schema.part.0' 'spark.sql.sources.schema.part.1''spark.sql.sources.schema.part.2' 'spark.sql.sources.schema.partCol.0' 'spark.sql.sources.schema.partCol.1'

    当我们将HDP升级到2.6.3时,Spark从2.2更新到了2.3,这导致了以下错误-

    Caused by: org.apache.spark.sql.AnalysisException: Cannot overwrite a path that is also being read from.;
    
    at org.apache.spark.sql.execution.command.DDLUtils$.verifyNotReadPath(ddl.scala:906)
    
    此错误发生在作业中,在该作业中,我们正在读取和写入同一路径。就像使用SCD逻辑的作业一样

    解决方案-

  • Set--conf“spark.sql.hive.convertMetastoreOrc=false”
  • 或者,更新作业,使其将数据写入临时表。然后从临时表中读取数据并将其插入到最终表中

  • 从spark中的配置单元表读取数据:

    val hconfig = new org.apache.hadoop.conf.Configuration()
    org.apache.hive.hcatalog.mapreduce.HCatInputFormat.setInput(hconfig , "dbname", "tablename")
    
    val inputFormat = (new HCatInputFormat).asInstanceOf[InputFormat[WritableComparable[_],HCatRecord]].getClass
    
    val data = sc.newAPIHadoopRDD(hconfig,inputFormat,classOf[WritableComparable[_]],classOf[HCatRecord])
    

    在执行以下操作的情况下,还会出现错误:“无法覆盖正在读取的路径”:

  • 您正在从视图“V”(执行您的逻辑)向配置单元表“a”进行“插入覆盖”
  • 该视图还引用了同一个表“A”。我发现这很困难,因为视图也是查询“A”的嵌套代码。糟糕透了

  • 这就像切割您所在的分支:-(

    在执行以下操作之前,您需要记住的是,您要覆盖的配置单元表应该是由配置单元DDL创建的,而不是由

    spark(df.write.saveAsTable("<table_name>"))
    
    spark(df.write.saveAsTable(“”)
    
    如果上述情况不正确,这将不起作用。 我在spark 2.3.0中对此进行了测试

    val tableReadDf=spark.sql("select * from <dbName>.<tableName>")
    val updatedDf=tableReadDf.<transformation> //any update/delete/addition 
    updatedDf.createOrReplaceTempView("myUpdatedTable")
    spark.sql("""with tempView as(select * from myUpdatedTable) insert overwrite table 
    <dbName>.<tableName> <partition><partition_columns> select * from tempView""")
    
    val tableReadDf=spark.sql(“选择*from.”)
    val updatedf=tableReadDf//任何更新/删除/添加
    updatedDf.createOrReplaceTempView(“myUpdatedTable”)
    spark.sql(“”),tempView为(从MyUpdateTable中选择*插入覆盖表
    。从临时视图“”中选择*)
    
    再次出现相同的错误。使用代码段编辑了我的问题抱歉,我已编辑了我的答案。RegisterAstetrable将创建内存中的表,从而产生相同的错误。使用saveAsTable时,它应该可以工作(但随后会将其写入磁盘,之后必须删除该表)。抱歉,我没有看到其他备选方案。答,我用同样的逻辑处理了这种情况,但我觉得这不划算。你突出强调的一点,即写入磁盘,是我想跳过的部分。无论如何,感谢你的帮助@cheseaux。如果你在这方面找到好的东西,请告诉我。干杯!!这完全安全吗?如果pp在写入目标表时失败?结果不是空的吗?(因此,当Thread自动重试你的应用程序时,你可能会提供错误的结果)我知道这很笨拙,但你不能截断原始表,然后将所有内容写回它吗?