日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)
- Impala 操作/读写 Kudu,使用druid连接池
- Kudu 原理、API使用、代码
- Kudu Java API 条件查询
- spark读取kudu表导出数据为parquet文件(spark kudu parquet)
- kudu 导入/导出 数据
- Kudu 分页查询的两种方式
- map、flatMap(流的扁平化)、split 的区别
- spark程序打包为jar包,并且导出所有第三方依赖的jar包
-
spark提交命令 spark-submit 的参数 executor-memory、executor-cores、num-executors、spark.default.parallelism分析
Spark Streaming 开窗函数 reduceByKeyAndWindow 统计一定时间内的热门词汇:DStream操作实战(reduceByKeyAndWindow开窗函数实现热门词汇统计)
1.架构图
2.实现流程
1.安装并启动生产者:yum -y install nc
首先在linux服务器上用YUM安装nc工具,nc命令是netcat命令的简称,它是用来设置路由器。我们可以利用它向某个端口发送数据。
2.通过netcat工具向指定的端口发送数据(作为数据的生产者):nc -lk 9999 # 输入 nc -lk 端口号 之后就能在交互模式下输入数据进行发送
3.编写Spark Streaming程序:
当前程序为以5秒划分数据为一个批次,然后每隔10s计算一次当前窗口大小为10s内的数据,即一次计算2个批次的函数据,
最后还将单词出现次数最多的前3位进行输出打印。
package cn.test.spark
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}
//Spark Streaming 开窗函数 reduceByKeyAndWindow 统计一定时间内的热门词汇
object SparkStreamingTCPWindowHotWords
{
def main(args: Array[String]): Unit =
{
//配置sparkConf参数
//setMaster("local[2]"):本地模式运行,启动两个线程
//设置master的地址local[N] ,n必须大于1,其中1个线程负责去接受数据,另一线程负责处理接受到的数据
val sparkConf: SparkConf = new SparkConf().setAppName("SparkStreamingTCPWindowHotWords").setMaster("local[2]")
//构建sparkContext对象
val sc: SparkContext = new SparkContext(sparkConf)
//设置日志输出的级别
sc.setLogLevel("WARN")
//构建StreamingContext对象,每个批处理的时间间隔,即以多少秒内的数据划分为一个批次 ,当前设置 以5秒内的数据 划分为一个批次,
//每一个batch(批次)就构成一个RDD数据集。DStream就是一个个batch(批次)的有序序列,时间是连续的,
//按照时间间隔将数据流分割成一个个离散的RDD数据集。
val scc: StreamingContext = new StreamingContext(sc, Seconds(5))
//使用“nc -lk 9999”生产数据并发送到9999端口,因此需要设置监听“IP:9999端口”,用来收集数据
val lines: ReceiverInputDStream[String] = scc.socketTextStream("192.168.25.100",9999)
//flatMap(_.split(" ")) 流的扁平化,最终输出的数据类型为一维数组Array[String],所有单词都被分割出来作为一个元素存储到同一个一维数组Array[String]
val words: DStream[String] = lines.flatMap(_.split(" "))
//每个单词记为1
//map((_,1))每个单词记为1,即(单词,1),表示每个单词封装为一个元祖,其key为单词,value为1,返回MapPartitionRDD数据
val wordAndOne: DStream[(String, Int)] = words.map((_,1))
/* reduceByKeyAndWindow函数的三个参数的意义:
1.第一个参数reduceFunc:需要一个函数
2.第二个参数windowDuration:
窗口长度:窗口框住的是一段时间内的数据,即窗口负责框住多少个批次的数据。
比如:设置窗口长度为10秒,然后如果以5秒内的数据划分为一个批次的话,
那么这个10秒长度的窗口便框住了2个批次的数据。
3.第三个参数slideDuration:
窗口滑动的时间长度:每隔“滑动指定的”时间长度计算一次,并且每当计算完毕后,窗口就往前滑动指定的时间长度。
比如:窗口滑动的时间长度为10秒的话,那么窗口每隔10秒计算一次,并且每当计算完毕后,窗口就往前滑动10秒。
比如:设置窗口长度为10秒,并且以5秒内的数据划分为一个批次的话,
那么这个10秒长度的窗口便框住了2个批次的数据,而如果又设置了窗口滑动的时间长度为10秒的话,
意味着窗口每隔10秒就计算一次,并且每当计算完毕后,窗口就往前滑动10秒。
4.结论:窗口长度和窗口滑动的时间长度必须为批次时间间隔的整数倍。
窗口长度和窗口滑动的时间长度必须一致相同。
窗口长度大于窗口滑动的时间长度,那么窗口仍然框住了部分已经计算过的批次数据,最终部分批次数据便会被重复计算
窗口长度小于窗口滑动的时间长度,那么窗口并无法框住部分还没计算过的批次数据,最终部分批次数据便丢失
*/
//当前程序为以5秒划分数据为一个批次,然后每隔10s计算一次当前窗口大小为10s内的数据,即一次计算2个批次的函数据
val result: DStream[(String, Int)] = wordAndOne.reduceByKeyAndWindow((a:Int,b:Int)=>a+b, Seconds(10), Seconds(10))
//将单词出现次数最多的前3位进行输出打印
val data=result.transform(rdd =>
{
//降序处理后,取前3位。false表示降序
//数组/元祖._下标值”,下标值从1开始。那么t._2 表示为取出单词出现次数Int来进行后面的sortBy降序排序操作
val dataRDD: RDD[(String, Int)] = rdd.sortBy(t=>t._2, false)
val sortResult: Array[(String, Int)] = dataRDD.take(3) //取前3位
println("--------------print top 3 begin--------------")
sortResult.foreach(println)
println("--------------print top 3 end--------------")
dataRDD
})
data.print()
scc.start()
scc.awaitTermination()
}
}
4.执行查看效果
1.先执行:nc -lk 9999
2.然后再执行以上程序代码
3.不断地在“nc -lk 9999”中输入不同的单词,观察IDEA控制台输出
4.现象:当前程序为以5秒划分数据为一个批次,然后每隔10s计算一次当前窗口大小为10s内的数据,即一次计算2个批次的函数据,
最后还将单词出现次数最多的前3位进行输出打印。