SparkSQL处理增量更新与全量更新

SparkSQL的增量更新

项目包结构:
在这里插入图片描述
工具类Utils:

package com.zhbr.utils

import java.util.Properties

import org.apache.spark.sql.execution.datasources.jdbc.JDBCOptions
import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}

/**
  * 连接数据库工具类
  */
object ConnOracleUtile {

  /**
    * 读取Oracle数据库
    * @param spark
    * @param dbtable
    * @return
    */
  def readPMSGSOracleData(spark:SparkSession,dbtable:String)={
    val data: DataFrame = spark.read.format("jdbc")
      .option("url", "jdbc:oracle:thin:@//10.212.242.XXX:11521/pmsgs")
      .option("dbtable", dbtable)
      .option("user", "qyw")
      .option("password", "XXX")
      .load()
    data
  }

  /**
    * 读取mysql数据库
    * @param spark
    * @param dbtable
    * @return
    */
  def readUSAPPData(spark:SparkSession,dbtable:String)={
    val data: DataFrame = spark.read.format("jdbc")
      .option("url", "jdbc:mysql://21.76.120.XX:3306/us_app")
      .option("dbtable", dbtable)
      .option("user", "root")
      .option("password", "XXX")
      .load()
    data
  }

  /**
    * 将数据写入到Mysql数据库(追加写入)
    * @param result
    * @param dbtable
    */
  def writeData(result:DataFrame,dbtable:String): Unit ={
    result.write.mode(SaveMode.Append).format("jdbc")
      .option(JDBCOptions.JDBC_URL,"jdbc:mysql://21.76.120.XX:3306/us_app?rewriteBatchedStatement=true")
      .option("user","root")
      .option("password","XXX")
      .option(JDBCOptions.JDBC_TABLE_NAME,dbtable)
      .option(JDBCOptions.JDBC_TXN_ISOLATION_LEVEL,"NONE")    //不开启事务
      .option(JDBCOptions.JDBC_BATCH_INSERT_SIZE,500)   //设置批量插入
      .save()
  }
}

接口trait:

package com.zhbr.`trait`

import org.apache.spark.SparkContext
import org.apache.spark.sql.sparkSession

trait ProcessDataSC {
  /**
    * 处理数据,实现不同的etl操作
    * @param spark
    */
  def process(sc: SparkContext,spark:SparkSession)
}

mianClass:

package com.zhbr.mainClass

import com.zhbr.process._
import org.apache.spark.sql.SparkSession

object DataProcessMain {
  def main(args: Array[String]): Unit = {

    //获取sparkSession
    val sparkSession = SparkSession.builder().appName(this.getClass.getSimpleName.filter(!_.equals('$'))).getOrCreate()

    //获取sparkContext
    val sparkContext = sparkSession.sparkContext

    //设置日志级别
    sparkContext.setLogLevel("WARN")

	//计算程序
    DLZZ.process(sparkContext,sparkSession)

    //释放资源
    sparkContext.stop()
    sparkSession.stop()
  }
}

计算程序:

package com.zhbr.process.run_date

import java.sql.Timestamp
import java.text.SimpleDateFormat
import java.util.{Calendar, Date}
import com.zhbr.`trait`.{ProcessDataSC}
import com.zhbr.utils.{ConnOracleUtile}
import org.apache.spark.SparkContext
import org.apache.spark.sql.execution.datasources.jdbc.JDBCOptions
import org.apache.spark.sql._

/**
 1. 运行数据
  */
object DLZZ extends ProcessDataSC{

  /**
    * 处理数据,实现不同的etl操作
    *
    * @param spark
    */
  override def process(sc:SparkContext,spark:SparkSession): Unit = {

	//读取增量数据的条件
    val tableName = "(select * from edc_exchange.T_EDC_TRAN_CURRENT_LINE where DATA_DATE=trunc(sysdate)-1) tableTemp"

	//读取电流日曲线表T_EDC_TRAN_CURRENT_LINE,获取数据
    val DLRQX_Data: DataFrame = ConnOracleUtile.readPMSGSOracleData(spark,tableName)

	//读取数据(终端停复电台区表)
    val ZDTFDTQData: DataFrame = ConnOracleUtile.readUSAPPData(spark,"pdwqy_qxzh_zdtfd_tg")
    
    //分别创建临时表
    DLRQX_Data.registerTempTable("DLRQX_Table")
    ZDTFDTQData.registerTempTable("ZDTFDTQData_table")

   	//计算过程(示意)
   	val DLZZData = spark.sql("select dl.*,zd.* from DLRQX_Table dl join ZDTFDTQData_table zd on dl.ssds = zd.ssdsid")

    //将最后的数据保存到表中(电流转置表)
    DLZZData.write.mode(SaveMode.Append).format("jdbc")
      .option(JDBCOptions.JDBC_URL,"jdbc:mysql://21.76.120.XX:3306/us_app?rewriteBatchedStatement=true")
      .option("user","root")
      .option("password","XXX")
      .option(JDBCOptions.JDBC_TABLE_NAME,"tempfinal_pdwqy_qxzh_dlzz")
      .option(JDBCOptions.JDBC_TXN_ISOLATION_LEVEL,"NONE")    //不开启事务
      .option(JDBCOptions.JDBC_BATCH_INSERT_SIZE,500)   //设置批量插入
      .save()
  }
}

以上计算步骤关键点:(以时间为参考做增量更新,每天凌晨抽取计算前一天的数据)

val tableName = "(select * from edc_exchange.T_EDC_TRAN_CURRENT_LINE where DATA_DATE=trunc(sysdate)-1) tableTemp"

注意:

  1. 查询增量数据的SQL需要重新命名,否则报错。如代码中的:
val tableName = "(select * from edc_exchange.T_EDC_TRAN_CURRENT_LINE where DATA_DATE=trunc(sysdate)-1) tableTemp"
  1. 增量更新的写入操作中,SaveMode必须为Append追加。

SparkSQL的全量更新

SparkSQL的全量更新非常简单,其实只需要在写入环节将SaveMode的模式修改为Overwrite即可。
但是这样也存在问题:

即OverWrite模式会先将原来的表删掉,然后spark根据字段推测各字段类型,重写生成新表。但新表的字段类型往往与原表有较大出入,如果是对字段的类型有着比较严格的要求,那最好不要使用OverWrite模式。

如本人公司项目原本的目标表字段类型:
在这里插入图片描述
如粗暴地使用OverWrite做全量更新,数据的字段类型会变为:
在这里插入图片描述
因此,如需要严格保持原表的字段类型还需要使用Append模式:

然后在程序执行前,执行一条删除原表数据的SQL语句:
truncate table 表名;
这样,现将原表数据删除,在追加新的数据,也可以完成全量更新。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值