Spark 2.x管理与开发-Spark Streaming-Spark Streaming进阶(三)【DStream中的转换操作(transformation+updateStateByKey)】

 

最后两个transformation算子需要重点介绍一下:

一、transform(func)

通过RDD-to-RDD函数作用于源DStream中的各个RDD,可以是任意的RDD操作,从而返回一个新的RDD

举例:在NetworkWordCount中,也可以使用transform来生成元组对

 

二、updateStateByKey(func)

操作允许不断用新信息更新它的同时保持任意状态。

定义状态-状态可以是任何的数据类型

定义状态更新函数-怎样利用更新前的状态和从输入流里面获取的新值更新状态

重写NetworkWordCount程序,累计每个单词出现的频率(注意:累计)

 

输出结果: 

 

注意:如果在IDEA中,不想输出log4j的日志信息,可以将log4j.properties文件(放在src的目录下)的第一行改为:

log4j.rootCategory=ERROR, console 

****************自己操作**************

一、transformation

Scala代码:

package streamingExamples

import org.apache.spark.SparkConf
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
import org.apache.spark.storage.StorageLevel
import org.apache.log4j.Logger
import org.apache.log4j.Level
/**
 * 知识点:
 * 1.创建StreamingContext 核心:DStream 离散流 
 * 2.DSteam的表现形式就是RDD,对二者的操作是一样的
 * 3.使用DStream把连续的数据流变成不连续的RDD
 * Spark Streaming最核心的内容
 */
object MyNetworkWordCount {
  def main(args: Array[String]): Unit = {
    //下面的两行代码定义日志级别,可以减少打印出来的日志
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    
    //一、创建运行时的环境
    //保证CPU的核数大于等于2,"local[2]"表示开启两个线程
    //一个线程用于读取数据,一个线程用于计算处理数据
    val conf=new SparkConf().setMaster("local[2]").setAppName("MyNetworkWordCount")
    //二、定时采样
    //因为SparkStreaming是将连续的数据流变成不连续的RDD,所以就是定时采样。
    //接收两个参数,其中:Seconds(3)是采样时间间隔,这里就是3秒
    val ssc=new StreamingContext(conf,Seconds(3))
    //三、创建DStream,从netcat服务器上读取数据
    //接收三个参数:地址,端口号,和RDD里缓存的位置一致(一般取默认值即可)
    val lines=ssc.socketTextStream("192.168.212.111", 1234, StorageLevel.MEMORY_ONLY)
    //四、分词
    val words=lines.flatMap(_.split(" "))
    //五、计数
//    val wordcount=words.map((_,1)).reduceByKey(_+_)
    val wordcount =words.transform(x=>x.map(x=>(x,1))) //每个单词后面都记一次数
    //注意:第一个x取得是RDD,x.map()是对RDD进行操作
    //六、打印
    wordcount.print()
    //注意:因为Spark Streaming程序是流式处理程序,所以可以不用关闭此程序
    //七、启动StreamingContext进行计算
    ssc.start()
    //八、等待任务结束
    ssc.awaitTermination()
  }
}

结果:

先启动虚拟机的nc服务器

[root@bigdata111 ~]# nc -l 1234

然后再运行此程序

接下来向服务器传数据

 

二、updateStateByKey

默认情况下,Spark Streaming 不记录之前的状态,每次发一条数据都是从0开始计算。

使用此算子来实现累加。

设置检查点-一般设置在HDFS上,将之前的数据都保存到该检查点目录里。

启动Zookeeper-三台同步启动

[root@bigdata111 ~]# zkServer.sh start

启动Hadoop

[root@bigdata111 ~]# cd /opt/module/HA/hadoop-2.8.4/

[root@bigdata111 hadoop-2.8.4]# cd sbin/

[root@bigdata111 sbin]# ./start-all.sh

 

[root@bigdata112 ~]# cd /opt/module/HA/hadoop-2.8.4/sbin/

[root@bigdata112 sbin]# ./start-all.sh

Scala代码:

package streamingExamples

import org.apache.spark.SparkConf
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
import org.apache.log4j.Logger
import org.apache.log4j.Level
import org.apache.spark.storage.StorageLevel

object MyTotalNetworkWordCount {
  def main(args: Array[String]): Unit = {
     //下面的两行代码定义日志级别,可以减少打印出来的日志
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    
    //一、创建运行时的环境
    //保证CPU的核数大于等于2,"local[2]"表示开启两个线程
    //一个线程用于读取数据,一个线程用于计算处理数据
    val conf =new SparkConf().setMaster("local[2]").setAppName("MyTotalNetworkWordCount")
    //二、定时采样
    //因为SparkStreaming是将连续的数据流变成不连续的RDD,所以就是定时采样。
    //接收两个参数,其中:Seconds(3)是采样时间间隔,这里就是3秒
    val ssc=new StreamingContext(conf,Seconds(3))
    //三、设置检查点目录-一般设置在HDFS上
    //注意:IP必须是Active状态主机的IP
    ssc.checkpoint("hdfs://192.168.212.111:9000/tmp_files/chkp0805")
    //四、创建DStream,从netcat服务器上读取数据
    //接收三个参数:地址,端口号,和RDD里缓存的位置一致(一般取默认值即可)
    //注意:IP可以不是Active状态主机的IP,只要是集群里的即可
    val lines=ssc.socketTextStream("192.168.212.112", 1234, StorageLevel.MEMORY_ONLY)
    //四、分词
    val words=lines.flatMap(_.split(" "))
    //五、计数
    val wordcount =words.map((_,1)) //每个单词后面都记一次数
    /**
     * 匿名函数
     * curreValues:当前的值是多少
     * previousValues:当前的结果是多少
     */
    val addFunc=(curreValues:Seq[Int],previousValues:Option[Int]) =>{
      //1)把当前值的序列进行累加
      val currentTotal=curreValues.sum
      //2)在之前的值上再进行累加
      //注意:如果没有值就取0 ,
//注释:Some---如果有值可以引用,就是用Some来包含这个值,Some也是Option的子类。
Some(currentTotal+previousValues.getOrElse(0)) } //自定义操作函数 val total =wordcount.updateStateByKey(addFunc) //六、打印 total.print() //注意:因为Spark Streaming程序是流式处理程序,所以可以不用关闭此程序 //七、启动StreamingContext进行计算 ssc.start() //八、等待任务结束 ssc.awaitTermination() } }

结果:

先启动虚拟机的nc服务器

[root@bigdata111~]# nc -l 1234

然后再运行此程序

如果创建HDFS上的新目录是采用下面的命令:

[root@bigdata111bin]# ./hadoop fs -mkdir -p /tmp_files

可能会出现的问题:

Permission denied: user=ASUS, access=WRITE, inode="/tmp_files":root:supergroup:drwxr-xr-x

尝试(一)

创建/tmp_files之后记得给它写的权限

 

[root@bigdata111 bin]# ./hadoop fs -chmod g+w /tmp_files

 

再次运行程序发现还是报错:

Permission denied: user=ASUS, access=WRITE, inode="/tmp_files":root:supergroup:drwxrwxr-x

尝试(二)

给予此目录最高权限:

[root@bigdata111 bin]# ./hadoop fs -chmod 777 /tmp_files

 

运行程序,可以正常运行了

接下来向服务器传数据

 

每3秒钟进行一次采样

 

 

 

 

 

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3