Spark DStream输出原语-foreachRDD&使用SparkSQL处理采集周期中的数据

DStream输出原语-foreachRDD

  1. 原语foreachRDD和transform原语有些类似,都可以让我们访问任意RDD,只不过后者必须要返回RDD,前者不用

  2. 在foreachRDD中,可以重用我们在Spark中实现的所有行动操作,比如常见的用例之一是把数据写到诸如MySQL的外部数据库中

import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
 * @Desc : 这里介绍两种保存数据的方式:
 *       1. 保存在文件中
 *       2. 保存在MySQL数据库中
 *       debug:因为数据库中要求主键不能重复,所以窗口的大小和滑动的步长必须保持一致
 */
object demo {
  def main(args: Array[String]): Unit = {
    // 创建配置文件对象
    // 注意Streaming程序执行至少需要2个线程,所以不能设置为local
    val conf: SparkConf = new SparkConf().setAppName("SparkStreaming11_Window_IO").setMaster("local[*]")
    // 创建SparkStreaming程序执行入口,并指定采集周期为3s
    val ssc = new StreamingContext(conf, Seconds(3))
    // 从指定端口读取数据
    val socketDS: ReceiverInputDStream[String] = ssc.socketTextStream("hadoop102", 9999)
    // 设置窗口的大小及滑动步长 以上两个值都应该是采集周期的整数倍
    val windowDS: DStream[String] = socketDS.window(Seconds(3), Seconds(3))
    // 业务逻辑
    val resDS: DStream[(String, Int)] = windowDS.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)

    resDS.print()
   //数据库连接4要素
    var driver = "com.mysql.jdbc.Driver"
    var url = "jdbc:mysql://hadoop102:3306/testSpark"
    var username = "root"
    var password = "rxdasd"

    // 输出数据到MySQL中
    /*
     1. 连接不能写在driver层面(序列化)
     2. 如果写在foreach则每个RDD中的每一条数据都创建,得不偿失,所以需要使用foreachPartition
     */
    resDS.foreachRDD(
      rdd => {
        rdd.foreachPartition {
          // 注册驱动
          Class.forName(driver)
          // 获取连接
          val conn: Connection = DriverManager.getConnection(url, username, password)
          // 声明数据库操作的SQL语句
          val sql: String = "insert into wc(word, cnt) values(?, ?)"
          // 创建数据库操作对象PrepareStatement
          val ps: PreparedStatement = conn.prepareStatement(sql)
          datas => {
            // 对当前分区内的数据进行遍历
            // 注意:这个foreach不是算子了,是集合的方法
            datas.foreach {
              case (word, cnt) => {
                // 给参数赋值
                ps.setString(1, word)
                ps.setInt(2, cnt)
                // 执行SQL
                ps.executeUpdate()
              }
            }
            // 关闭连接
            ps.close()
            conn.close()
          }
        }
      }
    )
    // 启动采集器
    ssc.start()
    // 等待采集结束之后,终止程序
    ssc.awaitTermination()
  }

}

使用SparkSQL处理采集周期中的数据

import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
 * @Desc : 这里介绍两种保存数据的方式:
 *       1是保存在文件中
 *       2是保存在MySQL数据库中
 *       debug:因为数据库中要求主键不能重复,所以窗口的大小和滑动的步长必须保持一致
 */
object demo {
  def main(args: Array[String]): Unit = {
    //创建配置文件对象
    //注意Streaming程序执行至少需要2个线程,所以不能设置为local
    val conf: SparkConf = new SparkConf().setAppName("z").setMaster("local[*]")
    //创建SparkStreaming程序执行入口
    //指定采集周期为3s
    val ssc = new StreamingContext(conf, Seconds(3))
    //从指定端口读取数据
    val socketDS: ReceiverInputDStream[String] = ssc.socketTextStream("hadoop102", 9999)
    //设置窗口的大小及滑动步长 以上两个值都应该是采集周期的整数倍
    val windowDS: DStream[String] = socketDS.window(Seconds(3), Seconds(3))
    //业务逻辑
    val resDS: DStream[(String, Int)] = windowDS
      .flatMap(_.split(" "))
      .map((_, 1))
      .reduceByKey(_ + _)
    //使用SparkSQL处理采集周期中的数据
    //采集SparkSession
    val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate()
    import spark.implicits._
    resDS.foreachRDD(
      rdd => {
        //将RDD转换为DataFrame
        val df: DataFrame = rdd.toDF("word", "count")
        //创建一个临时视图
        df.createOrReplaceTempView("table_word_count")
        //执行SQL
        spark.sql("select * from table_word_count").show()
      }
    )
    //启动采集器
    ssc.start()
    //等待采集结束之后,终止程序
    ssc.awaitTermination()
  }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值