学习 Spark 2(四):Spark 读写 Hive

启用 Hive

在使用 Builder 模式 SparkSession.Builder 创建 SparkSession 实例,通过调用 enableHiveSupport() 即可启用 Hive:

 SparkSession.builder()
        .master("yarn")
        .appName(appName)
        .enableHiveSupport()
        .getOrCreate()

在使用 Oozie 运行 Spark 任务时,需要手动设置系统参数,指定 Hive Metastore Server 地址:

System.setProperty("hive.metastore.uris", "thrift://hive_metastore:9083")  

读写 Hive 数据

//TODO

Hive 元数据

//TODO

高阶

根据 DataFrame 的 Schema 创建 Hive 表

一个🌰:

首先,DataFrame 创建临时视图:

userDF.createOrReplaceTempView(”user“)  

然后,根据临时视图创建 Hive 表:

import spark.sql

sql(  
  s"""
    |create table if not exists dw.user
    |using PARQUET
    |partitioned by (sex)
    |as select * from user
  """.stripMargin
)

Hive 动态分区

在向 Hive 分区表插入数据时,会自动根据分区字段的值,将数据插入到相应的分区中

动态分区配置:

  • hive.exec.dynamic.partition 在 DML/DDL 中是否允许动态分区,默认为 false
  • hive.exec.dynamic.partition.mode 在 strict 模式下,用户必须指定至少一个静态分区以防止用户意外覆盖所有分区。在 nostrict 模式下所有分区都是动态的。默认为 strict

请看👇的🌰:

配置:

SparkSession.builder()  
        .master("yarn")
        .appName(appName)
        .enableHiveSupport()
        .config("hive.exec.dynamic.partition", true) // 支持 Hive 动态分区
        .config("hive.exec.dynamic.partition.mode", "nonstrict") // 非严格模式
        .getOrCreate()

使用:

insert overwrite table dw.user  
partition(sex)  
select  
  *
from user  

参考:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML#LanguageManualDML-DynamicPartitionInserts

踩坑

使用 Hive 查询 Spark 写入的 Parquet 格式数据抛异常

Spark 版本 2.2.0

异常内容:

Failed with exception java.io.IOException:parquet.io.ParquetDecodingException: Can not read value at 1 in block 0 in file  

问题原因:

由于 Hive 和 Spark 针对 Decimal 数据类型的实现不一致:

  • Hive 使用 int32
  • Spark 使用标准的 Parquet 实现:1<= 精度 <= 9 使用 int32,1<= 精度 <= 18 使用 int64

解决方案:

设置 spark.sql.parquet.writeLegacyFormat 配置为 ture,Spark 在写入 Parquet 时会使用同 Hive 相同的实现