注意本案是以HDFS离线数据为例
1 spark操作hive
sparksql读取hive中的数据不需要hive参与 , 读取HDFS中的数据和mysql中的元数据信息即可
Sparksql本身就内置了hive功能
加载hive的数据,本质上是不需要hive参与的,因为hive的表数据就在hdfs中,hive的表定义信息在mysql中
不管数据还是定义,sparksql都可以直接去获取!
步骤:
- 要在工程中添加spark-hive的依赖jar
- 要在工程中添加mysql连接驱动依赖jar
- 下载三个文件 core-site.xml hdfs-site.xml hive-site.xml 到项目的resources下
依赖如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>doitedu-hange</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hudi</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-client</artifactId>
<version>0.8.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-spark-bundle_2.12</artifactId>
<version>0.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-hadoop-mr-bundle</artifactId>
<exclusions>
<exclusion>
<groupId>jackson-databind</groupId>
<artifactId>com.fasterxml.jackson.core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
<version>0.8.0</version>
</dependency>
<!-- <!– Spark的依赖引入 –>-->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>3.0.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.scala-lang</groupId>-->
<!-- <artifactId>scala-library</artifactId>-->
<!-- <version>2.12.10</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.12</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.12</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-avro_2.12</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.spark-project.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>1.2.1.spark2</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.12</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
</dependencies>
</project>
创建sparksession时需要调用.enableHiveSupport( )方法
System.setProperty("HADOOP_USER_NAME","root") ;
val sparkConf = new SparkConf().setAppName("testhive").setMaster("local[*]")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.set("datanucleus.schema.autoCreateTables","true")
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
代码如下
object LoadDadaFromHIve {
def main(args: Array[String]): Unit = {
// 获取Sparksession 对象
val session = SparkSession.builder()
.master("local[*]")
.appName("hive_demo")
.enableHiveSupport() // 开启对hive的支持
.getOrCreate()
/**
* 注意
* 1 直接编写sql语句即可操作hive 自动的读取resources下的三个配置文件
* 1) hive的元数据记录在lx01 机器的mysql中 lx01的mysql正常启动
* 2) hive的数据存储在HDFS 中的 hdfs正常启动
* 2 但是不要写 ;
* 3 select * from tb_name 直接操作的是default数据库中的表
* 4 操作自己的数据库中的表 数据库.表名
*/
session.sql("select * from doit14.emp") .show() //
session.stop()
}
}
注意: 启动mysql的元数据服务和hiveserver2服务
这一步执行成功以后 , 说明我们的项目环境是可以操作HIVE的 , 后面的就可以写HUDI的时候同步数据到HIVE表中
2 spark写数据到Hudi
添加依赖 , 准备环境
/**
* @Date 2021/10/19
* @Created by HANGGE WX 17710299606
* @Description
* 加载静态数据落地hudi
*/
object OpHive {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "root");
val sparkConf = new SparkConf().setAppName("testhive").setMaster("local[*]")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
//1 获取sparksession对象
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
import org.apache.spark.sql.functions._
// 2 加载数据 创建DF
val commitTime = System.currentTimeMillis().toString //生成提交时间
val schema = new StructType().add("id", DataTypes.StringType).add("name", DataTypes.StringType).add("age", DataTypes.IntegerType).add("city", DataTypes.StringType).add("score", DataTypes.DoubleType)
val df: DataFrame = sparkSession.read.schema(schema).csv("/user.txt")
.withColumn("ts", lit(commitTime))
//3 将DF 数据写到到hudi中
df.write.format("hudi")
.options(getQuickstartWriteConfigs()).
// 设置表类型 COW 概念在后面会涉及到
option(DataSourceWriteOptions.TABLE_TYPE_OPT_KEY, "COPY_ON_WRITE")
.option(DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY, "id") //设置主键
.option(DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY, "ts") // 数据更新时间
.option(DataSourceWriteOptions.KEYGENERATOR_CLASS_OPT_KEY, "org.apache.hudi.keygen.NonpartitionedKeyGenerator")
.option(TABLE_NAME, "tb_user_f") //hudi中的表
.mode(Append).
//hudi保存数据的地址
save("/hudi/tb_hudi_user_f");
}
}
查看指定目录中的数据
3 Spark写数据到Hudi同步到Hive
package com.doitedu.demo
import org.apache.hudi.DataSourceWriteOptions
import org.apache.spark.SparkConf
import org.apache.spark.sql.types.{DataTypes, StructType}
import org.apache.spark.sql.{DataFrame, SparkSession}
/**
* @Date 2021/10/19
* @Created by HANGGE
* @Description
* 加载HDFS上的数据生成DF
* 将DF写入到HUDI 同时同步到hive中
* 没有分区
*/
object OpHive_NoPartition {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "root");
val sparkConf = new SparkConf().setAppName("testhive").setMaster("local[*]")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.set("datanucleus.schema.autoCreateTables", "true")
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
insertData(sparkSession);
}
/**
* 插入数据 指定多个分区字段
* @param sparkSession
*/
def insertData(sparkSession: SparkSession) = {
import org.apache.hudi.QuickstartUtils._
import org.apache.hudi.config.HoodieWriteConfig._
import org.apache.spark.sql.SaveMode._
import org.apache.spark.sql.functions._
val commitTime = System.currentTimeMillis().toString //生成提交时间
val schema = new StructType()
.add("id", DataTypes.StringType)
.add("name", DataTypes.StringType)
.add("age", DataTypes.IntegerType)
.add("city", DataTypes.StringType)
.add("score", DataTypes.DoubleType)
.add("gender" , DataTypes.StringType)
// 加载数据同时添加一个 时间字段
val df: DataFrame = sparkSession.read.schema(schema).csv("/user3.txt")
.withColumn("ts", lit(commitTime))
df.show
// 注册hive驱动
Class.forName("org.apache.hive.jdbc.HiveDriver")
// 将数据写入到HUDI 同时同步到hive中
df.write.format("org.apache.hudi").
options(getQuickstartWriteConfigs()).
// 设置表类型 COW 概念在后面会涉及到
option(DataSourceWriteOptions.TABLE_TYPE_OPT_KEY, "COPY_ON_WRITE")
.option(DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY, "id") //设置主键
.option(DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY, "ts") // 数据更新时间
// .option(DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY, "city,gender")//指定多个分区字段
.option(DataSourceWriteOptions.KEYGENERATOR_CLASS_OPT_KEY , "org.apache.hudi.keygen.NonpartitionedKeyGenerator")
.option(TABLE_NAME, "tb_user_d") //hudi中的表
.option("hoodie.datasource.hive_sync.enable", true) // 同步数据到hive
.option("hoodie.datasource.hive_sync.table", "tb_user_d") //hive中的表
.option("hoodie.datasource.hive_sync.jdbcurl", "jdbc:hive2://doit01:10000")
// .option("hoodie.datasource.hive_sync.partition_fields", "city,gender") // hive分区字段 指定多个分区字段
.option("hoodie.datasource.write.table.type", "COPY_ON_WRITE")
.option("hoodie.embed.timeline.server", false)
.option("hoodie.datasource.hive_sync.partition_extractor_class", "org.apache.hudi.hive.NonPartitionedExtractor").
mode(Append).
save("/hudi/tb_hudi_user_d");
}
}
在hive中查看表
查看hive中表结构