SparkStreaming笔记02——wordcount、UpdateStateByKey、Transform 、Window Operations

一、SparkStreamingWC

这里的wordcount没有实现累加,

本地运行以下代码后,在mini1上输入:nc -lk 9999

然后输入单词,在idea的控制台上就可以出现单词统计结果


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

/**
  * 获取NetCat的数据并统计WordCount
  */
object StreamingWC {
  def main(args: Array[String]): Unit = {
    // 初始化环境
    val conf = new SparkConf().setAppName("StreamingWC").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val ssc: StreamingContext = new StreamingContext(sc, Durations.seconds(5))

    // 获取NetCat的数据
    val msg: ReceiverInputDStream[String] = ssc.socketTextStream("node03", 9999)

    // 统计
    val sumed: DStream[(String, Int)] = msg.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_+_)

    // 打印
    sumed.print()

 
    // 提交任务到集群
    ssc.start()
    // 线程等待,等待处理任务
    ssc.awaitTermination()
  }
}

 

ps:

1.在初始化ssc时,也可以不创建sc,直接val ssc: StreamingContext = new StreamingContext(conf, Durations.seconds(5))

2.不可以写成:setMaster("local"),这样只有一个线程,被接受消息的Reciver占用,负责计算的executor没有线程,所以就没有结果输出

3. 不可以写成println(sumed),

会报错:20/02/26 16:04:43 ERROR StreamingContext: Error starting the context, marking it as stopped
java.lang.IllegalArgumentException: requirement failed: No output operations registered, so nothing to execute

 

二、使用UpdateStateByKey实现带累加的wordcount

使用UpdateStateByKey,要指定checkpoint的位置,用来存放之前数据,然后使用UpdateStateByKey后,每次都取拉取这里的历史数据。

有个问题要注意,在hdfs上会产生很多小文件,这样很不好,所以可以写定时脚本,来删除数据,比如定时删除3天前的数据。或者选择放到mysql/redis中



import org.apache.spark.{HashPartitioner, SparkConf}
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.{Durations, StreamingContext}

/**
  * 将历史批次数据应用到当前批次进行聚合
  */
object UpdateStateByKeyDemo {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("updatestatebykey").setMaster("local[2]")
    val ssc = new StreamingContext(conf, Durations.milliseconds(2000))

    ssc.checkpoint("d://cp-20190716-1")  //checkpoint 的位置


    // 获取数据
    val msg = ssc.socketTextStream("node03", 9999)
    val tup: DStream[(String, Int)] = msg.flatMap(_.split(" ")).map((_, 1))
    // updateFunc: (Iterator[(K, Seq[V], Option[S])]) => Iterator[(K, S)], 用于将历史数据和当前批次数据进行计算的函数
    // partitioner: Partitioner, 指定分区器
    // rememberPartitioner: Boolean 是否记录分区信息
    val sumed: DStream[(String, Int)] = tup.updateStateByKey(
      func, new HashPartitioner(ssc.sparkContext.defaultParallelism), true)

    sumed.print()

    ssc.start()
    ssc.awaitTermination()
  }

  // (Iterator[(K, Seq[V], Option[S])]) => Iterator[(K, S)]
  // 其中:K代表数据中的key
  // Seq[V]代表当前批次单词出现的次数: Seq(1,1,1,1,.....)
  // Option[S]代表历史批次累加的结果,可能有值(Some),也可能没有值(None),获取数据的时候可以用getOrElse
  val func = (it: Iterator[(String, Seq[Int], Option[Int])]) => {
    // x代表it中的其中一个元素,元素就是一个元组
    it.map(x => {
      (x._1, x._2.sum + x._3.getOrElse(0))
    })
  }

}

三、Transform 

Transform原语允许DStream上执行任意的RDD-to-RDD函数。通过该函数可以方便的扩展Spark API。此外,MLlib(机器学习)以及Graphx也是通过本函数来进行结合的。

简单来说,SparkStreaming算子有限,使用Transform 就能在SparkStreaming中使用RDD的算子,

比如:


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

/**
  * 获取NetCat的数据并统计WordCount
  */
object TransformWC {
  def main(args: Array[String]): Unit = {
    // 初始化环境
    val conf = new SparkConf().setAppName("StreamingWC").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val ssc: StreamingContext = new StreamingContext(sc, Durations.seconds(5))

    // 获取NetCat的数据
    val msg: ReceiverInputDStream[String] = ssc.socketTextStream("node03", 9999)

    // 统计
    val sumed: DStream[(String, Int)] = r1.transform(x=>{
      x.flatMap(_.split(" ")).map(x=>(x,1)).reduceByKey(_+_).sortBy(_._2,false)
    })

    // 打印
    sumed.print()

 
    // 提交任务到集群
    ssc.start()
    // 线程等待,等待处理任务
    ssc.awaitTermination()
  }
}

四、Window Operations

Window Operations有点类似于Storm中的State,可以设置窗口的大小和滑动窗口的间隔来动态的获取当前Steaming的允许状态

示范:


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

/**
  * 用窗口操作的方式进行单词计数
  * 窗口大小10秒,滑动间隔10秒
  */
object WindowOperationsDemo {
  def main(args: Array[String]): Unit = {
    // 初始化环境
    val conf = new SparkConf().setAppName("WindowOperationsDemo").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val ssc: StreamingContext = new StreamingContext(sc, Durations.seconds(5))

    // 获取NetCat的数据
    val msg: ReceiverInputDStream[String] = ssc.socketTextStream("node03", 6666)

    // 统计
    val tup: DStream[(String, Int)] = msg.flatMap(_.split(" ")).map((_, 1))
    val sumed: DStream[(String, Int)] =
      tup.reduceByKeyAndWindow((x: Int, y: Int) => (x + y), Durations.seconds(10), Durations.seconds(10))


    // 打印
    sumed.print()

    // 提交任务到集群
    ssc.start()
    // 线程等待,等待处理任务
    ssc.awaitTermination()
  }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值