注意本案是以HDFS离线数据为例

1 spark操作hive 

sparksql读取hive中的数据不需要hive参与 , 读取HDFS中的数据和mysql中的元数据信息即可

Sparksql本身就内置了hive功能

加载hive的数据,本质上是不需要hive参与的,因为hive的表数据就在hdfs中,hive的表定义信息在mysql中

不管数据还是定义,sparksql都可以直接去获取!

步骤:

  1. 要在工程中添加spark-hive的依赖jar
  2. 要在工程中添加mysql连接驱动依赖jar
  3. 下载三个文件 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>

sparksql 表切片 sparksql hudi_sparksql 表切片

创建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");
  }
}

查看指定目录中的数据

sparksql 表切片 sparksql hudi_apache_02

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中查看表 

sparksql 表切片 sparksql hudi_big data_03

查看hive中表结构 

sparksql 表切片 sparksql hudi_spark_04