目录

  • ​​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()
}