package com.streaming
import org.apache.spark.sql.SparkSession
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.{Durations, StreamingContext}
object Demo01WordCountOnStreaming {
def main(args: Array[String]): Unit = {
//先构建SparkSession
val spark: SparkSession = SparkSession
.builder()
.appName("Demo01WordCountOnStreaming")
.master("local[2]") // 在SparkStreaming中接受数据需要一直占用一个线程,所以这里需要至少2个及以上的线程数
.getOrCreate()
// 构建Spark Streaming 环境
/**
* duration:指定批次的大小
* 在这里相当于每隔5s中会将这5s中所接受到的数据封装成一个小的批次,并启动一个任务完成该小批次数据的计算,得到结果
* 这5s并不是按照任务启动之后每隔5s计算一次,而是以0点0时0分0毫秒开始计算,每隔5s相当于会有一个触发点,可以触发任务的执行
* 任务刚启动时,第一个批次可以没有达到5s的数据但也会触发任务计算
*/
val ssc: StreamingContext = new StreamingContext(spark.sparkContext, Durations.seconds(5))
// 使用Socket模拟消息队列
/**
* nc -lk 8888 建立Socket连接在xshell中
*/
/**
* Spark Core基于RDD
* Spark SQL基于DataFrame
* Spark Streaming 中的编程模型为 DStream
*/
val ds: DStream[String] = ssc.socketTextStream("master", 8888)
ds.print()//DStream的打印方式
//将每一行数据进行切分 并将每一个单词展开
val wordDS: DStream[String] = ds.flatMap(_.split(","))
//将每一个单词变成一个二元组,二元组的第二个元素为1
val wordKVDS: DStream[(String, Int)] = wordDS.map(word => (word, 1))
// 统计每个单词的数量
// 只能对当前批次接受到的数据进行统计 并不会考虑历史状态(某一时刻某一批次计算的到的结果)
// 如果需要考虑历史状态,则可以使用有状态算子
val wordCnt: DStream[(String, Int)] = wordKVDS.reduceByKey(_ + _)
wordCnt.print()
//启动任务
ssc.start()
ssc.awaitTermination()
ssc.stop()
}
}