从 Spark 写入 Hive 表,指定 CSV 作为格式

Posted

技术标签:

【中文标题】从 Spark 写入 Hive 表,指定 CSV 作为格式【英文标题】:Writing Hive table from Spark specifying CSV as the format 【发布时间】:2017-08-15 00:00:31 【问题描述】:

我在从 Spark 写入 Hive 表时遇到问题。下面的代码工作得很好;我可以编写表格(默认为 Parquet 格式)并在 Hive 中读回:

df.write.mode('overwrite').saveAsTable("db.table")

hive> describe table;
OK
val           string
Time taken: 0.021 seconds, Fetched: 1 row(s)

但是,如果我指定格式应该是 csv:

df.write.mode('overwrite').format('csv').saveAsTable("db.table")

然后我可以保存表,但 Hive 无法识别架构:

hive> describe table;
OK
col                     array<string>           from deserializer
Time taken: 0.02 seconds, Fetched: 1 row(s)

另外值得注意的是,我可以手动创建一个Hive表,然后insertInto它:

spark.sql("create table db.table(val string)")
df.select('val').write.mode("overwrite").insertInto("db.table")

这样做,Hive 似乎可以识别架构。但这很笨拙,而且我无论如何也想不出一种自动化模式字符串的方法。

【问题讨论】:

Dataframe 的架构是什么?数据中有逗号吗? df.printSchema的输出是什么? 为什么是“笨重”?您想要创建一个符合 Hive 的数据集,因此使用符合 Hive 的方法来创建它似乎是合理的。为了记录,Parquet 更糟糕,因为默认情况下 Spark 不使用与 Hive 相同的二进制编码......并且没有记录覆盖该默认值的方法 cf。 [SPARK-20937] @cricket_007 和 Ankush Singh:架构和数据很简单,我尝试过各种方法。即使是具有单个整数列的 DataFrame 也无法写入 Hive 可以读取的模式(使用 csv 格式)。 @samsonScharfrichter 我说“笨拙”是因为您必须编写一个符合 hive 的模式字符串。当使用默认格式的saveAsTable 时,您不必这样做。我没有遇到 Parquet 的二进制编码问题。感谢您的提醒! 【参考方案1】:

那是因为Hive SerDe默认不支持csv

如果你坚持使用csv格式,创建表格如下:

CREATE TABLE my_table(a string, b string, ...)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
   "separatorChar" = "\t",
   "quoteChar"     = "'",
   "escapeChar"    = "\\"
)  
STORED AS TEXTFILE;

并通过df.write.insertInto插入数据

更多信息:

https://cwiki.apache.org/confluence/display/Hive/CSV+Serde

【讨论】:

感谢您的信息。我提到过这种策略有效,但它很笨拙,因为您必须生成模式字符串 (a string, b string, ...)。这是 Spark 编写一个 Spark 和 Hive 都可以读取的表的唯一解决方案吗?【参考方案2】:

您正在创建一个文本格式的表格并尝试将 CSV 数据插入其中,这可能会遇到问题。因此,正如张彤在回答中所建议的那样,使用 hive OpenCSVSerde 创建 hive 表。

之后,如果你对 Hive 查询语言比对数据框更熟悉,你可以试试这个。

df.registerTempTable("temp")
spark.sql("insert overwrite db.table select * from temp")

【讨论】:

我不确定我是否完全遵循。 saveAsTable 的默认值是 Parquet,它工作得很好。当然,Hive SerDe 本身也不支持 Parquet。对吗? 很抱歉给您带来了困惑。我的实际意思是,使用所需的任何格式创建配置单元表。然后只需将数据框中的数据写入配置单元表。这样,你在写的时候就不用担心格式了。我提供了基本的替代代码 sn-p 从数据帧写入配置单元表,而不用担心格式。 Hive 原生支持 Parquet SerDe。请参考cwiki.apache.org/confluence/display/Hive/Parquet 那么说 Hive 原生支持 Parquet 但不支持 CSV 公平吗?【参考方案3】:

发生这种情况是因为 csv 的 HiveSerde 与 Spark 使用的不同。 Hive 默认使用 TEXTFORMAT 并且必须在创建表时指定分隔符。

一种选择是在从 spark 写入时使用 insertInto API 而不是 saveAsTable。在使用 insertInto 时,Spark 会将 Dataframe 的内容写入指定的表。但它要求数据框的架构与表的架构相同。列的位置在这里很重要,因为它忽略了列名。

Seq((5, 6)).toDF("a", "b").write.insertInto("t1")

【讨论】:

问题首先是创建 Hive 表。我同意如果它已经存在,您可以使用insertInto。但我不知道有一种简单的方法可以从 Spark 中生成表(如果它尚不存在)。

以上是关于从 Spark 写入 Hive 表,指定 CSV 作为格式的主要内容,如果未能解决你的问题,请参考以下文章

Spark SQL写入Hive,同分区overwrite,不同分区insert

在 Hive 表 hdfs 文件夹中写入文件并使其可用于从 Hive 查询

将 Spark Dataframe 写入 HDP2.6 中的 Hive 可访问表

.csv 不是 Select Hive Query 上的 SequenceFile 错误

Hive:Spark中如何实现将rdd结果插入到hive1.3.1表中

Logstash同步Hive和Clickhouse