Spark Streaming状态管理函数(三)—MapWithState的使用(scala版)

关于mapWithState

  需要自己写一个匿名函数func来实现自己想要的功能。如果有初始化的值得需要,可以使用initialState(RDD)来初始化key的值。 另外,还可以指定timeout函数,该函数的作用是,如果一个key超过timeout设定的时间没有更新值,那么这个key将会失效。这个控制需要在func中实现,必须使用state.isTimingOut()来判断失效的key值。如果在失效时间之后,这个key又有新的值了,则会重新计算。如果没有使用isTimingOut,则会报错。

注意事项

  下面程序是使用idea编写的,使用的是scala语言,在程序中master(“local[2]”)设置为本地模式([]中的数指定的是线程数,不能少于2,否则看不到结果。主要是因为spark需要启动一个线程receiver来循环接收数据,一个Executor来接收数据,如果少于2线程不够将不能打印出结果。),在window上运行的。使用的spark版本是2.3.0,在2.x以后的版本,基本采用SparkSession来进行操作。同时,想要运行程序你的服务器上还必须要安装netcat这个软件,使用yum install nc进行安装(注意安全配置好yum源,DNS才能下载安装),使用命令nc -lk 6666开启服务发送数据。最后在运行程序前还需要导入spark、scala相应的依赖包。

示例代码

package spark2x

import org.apache.spark.sql.SparkSession
import org.apache.spark.streaming.dstream.{DStream, MapWithStateDStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, State, StateSpec, StreamingContext}

/**
* 类名  MapWithState
* 作者   彭三青
* 创建时间  2018-12-01 14:08
* 版本  1.0
* 描述: $
*/

object MapWithState {
// 设置本地运行模式
def main(args: Array[String]): Unit = {
  val spark = SparkSession.builder()
    .master("local[2]")
    .appName("MapWithState")
    .getOrCreate()

  // 创建一个context,批次间隔为2秒钟,
  val ssc: StreamingContext = new StreamingContext(spark.sparkContext, Seconds(3))

  // 设置checkpoint目录
  ssc.checkpoint("hdfs://SC01:8020/user/tmp/cp-20181201-2")

  // 创建一个ReceiverInputDStream,从服务器端的netcat接收数据。
  // 服务器主机名SC01(SC01已在Window上的hosts文件中做了映射,没做映射的则写ip就OK了),监听端口为6666
  val line: ReceiverInputDStream[String] = ssc.socketTextStream("SC01", 6666)

  // 对接收到的数据进行处理,进行切割,分组形式为(day, 1) (word 1)
  val wordsStream: DStream[(String, Int)] = line.flatMap(_.split(" ")).map((_, 1))

  val wordCount: MapWithStateDStream[String, Int, Int, Any] = wordsStream.mapWithState(StateSpec.function(func).timeout(Seconds(30)))

  wordCount.print()

  ssc.start()

  ssc.awaitTermination()
}

/**
  * 定义一个函数,该函数有三个类型word: String, option: Option[Int], state: State[Int]
  * 其中word代表统计的单词,option代表的是历史数据(使用option是因为历史数据可能有,也可能没有,如第一次进来的数据就没有历史记录),state代表的是返回的状态
  */
val func = (word: String, option: Option[Int], state: State[Int]) => {
  if(state.isTimingOut()){
    println(word + "is timeout")
  }else{
    // getOrElse(0)不存在赋初始值为零
    val sum = option.getOrElse(0) + state.getOption().getOrElse(0)
    // 单词和该单词出现的频率/ 获取历史数据,当前值加上上一个批次的该状态的值
    val wordFreq = (word, sum)
    // 更新状态
    state.update(sum)
    wordFreq
  }
}
}

运行

  服务器运行nc

  idea端运行编写好的程序
  服务器发送数据

  控制台显示结果

结论

  mapWithState它会按照时间线在每一个批次间隔返回之前的发生改变的或者新的key的状态,不发生变化的不返回;同时mapWithState可以不用设置checkpoint,返回的数据量少。而updateStateByKey统计的是全局Key的状态,就算没有数据输入也会在每个批次的时候返回之前的Key的状态,当数据量大时而且使用checkpoint会占用较大的存储。因此,mapWithState性能和效率要比updateStateByKey好。




第一篇:Spark Streaming状态管理函数(一)——updateStateByKey和mapWithState
第二篇:Spark Streaming状态管理函数(二)——updateStateByKey的使用(scala版)

更新时间
2018-12-10 更换了图片错误,改变了代码块的风格
2019-09-23 修改并增加了文章末尾的内容
2019-10-31 代码部分粘贴错误更新
## 最后
 ​ 本人想组建一个技术交流群,有兴趣的可以扫码加入,用于学习和交流,希望和大家一起学习一起进步。
 ​  ​ QQ群:814507419
在这里插入图片描述

 ​  ​ 微信群:由于微信群二维码会失效,大家可以加我微信,然后拉大家进群期待和大家一起进步一起学习。微信号18397716181
在这里插入图片描述

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值