Spark操作Hive分割槽表

weixin_33850890發表於2018-12-07

我的原創地址:https://dongkelun.com/2018/12/04/sparkHivePatition/

前言

前面學習總結了Hive分割槽表,現在學習總結一下Spark如何操作Hive分割槽表,包括利用Spark DataFrame建立Hive的分割槽表和Spark向已經存在Hive分割槽表裡插入資料,並記錄一下遇到的問題以及如何解決。

1、Spark建立分割槽表

只寫主要程式碼,完整程式碼見附錄

val data = Array(("001", "張三", 21, "2018"), ("002", "李四", 18, "2017"))
val df = spark.createDataFrame(data).toDF("id", "name", "age", "year")
//可以將append改為overwrite,這樣如果表已存在會刪掉之前的表,新建表
df.write.mode("append").partitionBy("year").saveAsTable("new_test_partition")


然後在Hive命令列裡看一下,新建的表是否有分割槽欄位year
用命令

desc new_test_partition;

show create table new_test_partition;

根據下面的結果可以看到新建的表確實有分割槽欄位year

hive> desc new_test_partition;
OK
id                      string                                      
name                    string                                      
age                     int                                         
year                    string                                      
         
# Partition Information      
# col_name              data_type               comment             
         
year                    string                                      
Time taken: 0.432 seconds, Fetched: 9 row(s)

2、向已存在的表插入資料

2.1 Spark建立的分割槽表

  • 這種情況其實和建表語句一樣就可以了
  • 不需要開啟動態分割槽
df.write.mode("append").partitionBy("year").saveAsTable("new_test_partition")

當然也有其他方式插入資料,會在後面講到。

2.2 在Hive命令列建立的表

  • 這裡主要指和Spark建立的表的檔案格式不一樣,Spark預設的檔案格式為PARQUET,為在命令列Hive預設的檔案格式為TEXTFILE,這種區別,也導致了異常的出現。
  • 需要開啟動態分割槽
  • 不開啟會有異常:
Exception in thread "main" org.apache.spark.SparkException: Dynamic partition strict mode requires at least one static partition column. To turn this off set hive.exec.dynamic.partition.mode=nonstrict

2.2.1 建表

Hive分割槽表學習總結的建表語句建表(之前已經建過就不用重複建了)。

create table test_partition (
id string comment 'ID', 
name string comment '名字',
age int comment '年齡'
)
comment '測試分割槽'
partitioned by (year int comment '年')
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;

2.2.2 異常

試著用上面的插入語句插入資料

df.write.mode("append").partitionBy("year").saveAsTable("test_partition")

丟擲異常

Exception in thread "main" org.apache.spark.sql.AnalysisException: The format of the existing table dkl.test_partition is `HiveFileFormat`. It doesn't match the specified format `ParquetFileFormat`.;

原因就是上面說的檔案格式不一致造成的。

2.2.3 解決辦法

用fomat指定格式

df.write.mode("append").format("Hive").partitionBy("year").saveAsTable("test_partition")

2.3 其他方法

df.createOrReplaceTempView("temp_table")
sql("insert into test_partition select * from temp_table")
df.write.insertInto("test_partition")

其中insertInto不需要也不能將df進行partitionBy,否則會丟擲異常

df.write.partitionBy("year").insertInto("test_partition")
Exception in thread "main" org.apache.spark.sql.AnalysisException: insertInto() can't be used together with partitionBy(). Partition columns have already be defined for the table. It is not necessary to use partitionBy().;

3、完整程式碼

package com.dkl.blog.spark.hive

import org.apache.spark.sql.SparkSession

/**
 * 部落格:Spark操作Hive分割槽表
 * https://dongkelun.com/2018/12/04/sparkHivePatition/
 *
 */
object SparkHivePatition {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession
      .builder()
      .appName("SparkHive")
      .master("local")
      .config("spark.sql.parquet.writeLegacyFormat", true)
      .enableHiveSupport()
      .getOrCreate()

    import spark.sql

    val data = Array(("001", "張三", 21, "2018"), ("002", "李四", 18, "2017"))

    val df = spark.createDataFrame(data).toDF("id", "name", "age", "year")
    //建立臨時表
    df.createOrReplaceTempView("temp_table")

    //切換hive的資料庫
    sql("use dkl")
    //    1、建立分割槽表,可以將append改為overwrite,這樣如果表已存在會刪掉之前的表,新建表
    df.write.mode("append").partitionBy("year").saveAsTable("new_test_partition")
    //2、向Spark建立的分割槽表寫入資料
    df.write.mode("append").partitionBy("year").saveAsTable("new_test_partition")
    sql("insert into new_test_partition select * from temp_table")
    df.write.insertInto("new_test_partition")

    //開啟動態分割槽
    sql("set hive.exec.dynamic.partition.mode=nonstrict")
    //3、向在Hive裡用Sql建立的分割槽表寫入資料,丟擲異常
    //    df.write.mode("append").partitionBy("year").saveAsTable("test_partition")

    // 4、解決方法
    df.write.mode("append").format("Hive").partitionBy("year").saveAsTable("test_partition")

    sql("insert into test_partition select * from temp_table")
    df.write.insertInto("test_partition")
    //這樣會丟擲異常
    //    df.write.partitionBy("year").insertInto("test_partition")

    spark.stop
  }
}

相關閱讀

相關文章