我试图在DataFrame
模式下Hive
写S3
表(Overwrite
}(我的申请需要)并需要在DataFrameWriter的两种方法(Spark / Scala)。根据我在documentation中可以阅读的内容,df.write.saveAsTable
在以下方面与df.write.insertInto
不同:
saveAsTable
使用基于列名称的解析,而insertInto
使用基于位置的解析 saveAsTable
会更加关注现有表格的基础架构以制定某些决议总体而言,它给我的印象是saveAsTable
只是insertInto
的更智能的版本。或者,根据用例,可能更喜欢insertInto
但是这些方法中的每一种都有自己的一些注意事项,例如saveAsTable
的性能损失(因为它包含更多功能)?除了在文档中讲述(不是很清楚)的内容之外,他们的行为还有其他差异吗?
修改-1
文档说明insertInto
将DataFrame的内容插入指定的表
和saveAsTable
在表已存在的情况下,此函数的行为 取决于模式功能
指定的保存模式
现在我可以列出我的怀疑
insertInto
总是希望表存在吗?SaveMode
会对insertInto
产生影响吗?saveAsTable
与SaveMode.Append
和insertInto
之间的区别是什么?insertInto
与SaveMode.Overwrite
有什么关系吗?答案 0 :(得分:15)
免责声明我已经探索了insertInto
一段时间了,虽然我离这个领域的专家很远,但我还是分享了更多的研究结果好。
insertInto
总是希望表存在吗?
Yes(根据表名和数据库)。
此外,并非所有表都可以插入,即(永久)表,临时视图或临时全局视图都可以,但不是:
一张表格
基于RDD的表
SaveModes对insertInto有什么影响吗?
(最近这也是我的问题!)
是的,但只有SaveMode.Overwrite。在考虑insertInto
之后,其他3种保存模式没有多大意义(因为它只是插入数据集)。
如果表已经存在,saveAsTable与SaveMode.Append和insertInto之间的区别是什么?
这是一个非常好的问题!我没有说,但是让我们只看一个例子(希望证明某事)。
scala> spark.version
res13: String = 2.4.0-SNAPSHOT
sql("create table my_table (id long)")
scala> spark.range(3).write.mode("append").saveAsTable("my_table")
org.apache.spark.sql.AnalysisException: The format of the existing table default.my_table is `HiveFileFormat`. It doesn't match the specified format `ParquetFileFormat`.;
at org.apache.spark.sql.execution.datasources.PreprocessTableCreation$$anonfun$apply$2.applyOrElse(rules.scala:117)
at org.apache.spark.sql.execution.datasources.PreprocessTableCreation$$anonfun$apply$2.applyOrElse(rules.scala:76)
...
scala> spark.range(3).write.insertInto("my_table")
scala> spark.table("my_table").show
+---+
| id|
+---+
| 2|
| 0|
| 1|
+---+
insertInto和SaveMode.Overwrite有什么意义吗?
我想是的,因为它非常关注SaveMode.Overwrite
。它只是重新创建目标表。
spark.range(3).write.mode("overwrite").insertInto("my_table")
scala> spark.table("my_table").show
+---+
| id|
+---+
| 1|
| 0|
| 2|
+---+
Seq(100, 200, 300).toDF.write.mode("overwrite").insertInto("my_table")
scala> spark.table("my_table").show
+---+
| id|
+---+
|200|
|100|
|300|
+---+
答案 1 :(得分:6)
我想指出SPARK中SaveAsTable
和insertInto
之间的主要区别。
在分区表overwrite
中,对于SaveAsTable
和insertInto
,SaveMode的工作方式有所不同。
请考虑以下示例。我正在使用SaveAsTable
方法创建分区表。
hive> CREATE TABLE `db.companies_table`(`company` string) PARTITIONED BY ( `id` date);
OK
Time taken: 0.094 seconds
import org.apache.spark.sql._*
import spark.implicits._
import org.apache.spark.sql._
scala>val targetTable = "db.companies_table"
scala>val companiesDF = Seq(("2020-01-01", "Company1"), ("2020-01-02", "Company2")).toDF("id", "company")
scala>companiesDF.write.mode(SaveMode.Overwrite).partitionBy("id").saveAsTable(targetTable)
scala> spark.sql("select * from db.companies_table").show()
+--------+----------+
| company| id|
+--------+----------+
|Company1|2020-01-01|
|Company2|2020-01-02|
+--------+----------+
现在我要添加2个新行和2个新分区值。
scala> val companiesDF = Seq(("2020-01-03", "Company1"), ("2020-01-04", "Company2")).toDF("id", "company")
scala> companiesDF.write.mode(SaveMode.Append).partitionBy("id").saveAsTable(targetTable)
scala>spark.sql("select * from db.companies_table").show()
+--------+----------+
| company| id|
+--------+----------+
|Company1|2020-01-01|
|Company2|2020-01-02|
|Company1|2020-01-03|
|Company2|2020-01-04|
+--------+----------+
如您所见,表中添加了2个新行。
现在让我们说我想Overwrite
对2020-01-02数据进行分区。
scala> val companiesDF = Seq(("2020-01-02", "Company5")).toDF("id", "company")
scala>companiesDF.write.mode(SaveMode.Overwrite).partitionBy("id").saveAsTable(targetTable)
根据我们的逻辑,只有分区2020-01-02应该被覆盖,但是SaveAsTable
的情况有所不同。它将覆盖enter表,如下所示。
scala> spark.sql("select * from db.companies_table").show()
+-------+----------+
|company| id|
+-------+----------+
|Company5|2020-01-02|
+-------+----------+
因此,如果我们只想使用SaveAsTable
覆盖表中的某些分区,则不可能。
请参阅此链接以获取更多详细信息。 https://towardsdatascience.com/understanding-the-spark-insertinto-function-1870175c3ee9
答案 2 :(得分:0)
在将数据从spark 2.xx插入到现有的Hive动态分区表中时,我要考虑的另一个重要点:
df.write.mode("append").insertInto("dbName"."tableName")
以上命令将固有地映射“ df”中的数据,并且仅将新分区附加到现有表中。
希望,它在决定何时使用“ insertInto”时增加了另一点。
答案 3 :(得分:0)
我最近开始将Hive脚本转换为Spark,但我仍在学习。
我注意到saveAsTable和insertInto有一种重要的行为,尚未讨论。
df.write.mode(“ overwrite”)。saveAsTable(“ schema.table”)删除现有表“ schema.table”,并基于'df'模式重新创建新表。现有表的架构变得无关紧要,不必与df匹配。因为我的现有表是ORC,而创建的新表是镶木地板(Spark Default),所以我被这种行为所困扰。
df.write.mode(“ overwrite”)。insertInto(“ schema.table”)不会删除现有表,并且希望现有表的架构与'df'架构匹配。
我同时使用了两个选项检查了表的创建时间,并再次确认了行为。
原始表存储为ORC- 2019年9月4日星期三21:27:33 GMT
saveAsTable之后(存储更改为Parquet)-格林尼治标准时间2019年9月4日星期三21:56:23 (创建时间已更改)
删除并重新创建的原始表(ORC)- 2019年9月4日星期三21:57:38
insertInto之后(仍然是ORC)- 2019年9月4日星期三21:57:38 GMT (创建时间未更改)