DStream的转化操作

DStream API提供的与转化操作相关的方法如下:

如下举例详解transform(func) 方法和 updateStateByKey(func) 方法:

(1)、transform(func) 方法

transform 方法及类似的 transformWith(func) 方法允许在 DStream 上应用任意 RDD-to-RDD 函数,它们可以被应用于未在 DStream API 中暴露的任何 RDD 操作中。 下面举例演示如何使用transform(func) 方法将一行语句分隔成多个单词,具体步骤如下: A、在Liunx中执行命令nc –lk 9999 启动服务器且监听socket服务,并且输入数据I like spark streaming and Hadoop,具体命令如下: B、打开IDEA开发工具,创建一个Maven项目,并且配置pom.xml文件,引入Spark Streaming相关的依赖包,pom.xml文件配置具体如下: <!--设置依赖版本号-->

<properties>
    <spark.version>2.1.1</spark.version>
    <scala.version>2.11</scala.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_${scala.version}</artifactId>
        <version>${spark.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming_${scala.version}</artifactId>
        <version>${spark.version}</version>
    </dependency>
</dependencies>

注意:配置好pom.xml文件后,需要在项目的/src/main和/src/test目录下分别创建scala目录。 C、在项目的/src/main/scala目录下创建包,接着创建一个名为TransformTest的scala类,主要用于编写SparkStreaming应用程序,实现一行语句分隔成多个单词的功能,具体代码如下(带注释):

package SparkStreaming

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

object TransformTest {
  def main(args: Array[String]): Unit = {
    //创建SparkConf对象
    val sparkconf = new SparkConf().setAppName("TransformTest").setMaster("local[2]")
    //创建SparkContext对象
    val sc = new SparkContext(sparkconf)
    //设置日志级别
    sc.setLogLevel("WARN")
    //创建StreamingContext,需要创建两个参数,分别为SparkContext和批处理时间间隔
    val ssc = new StreamingContext(sc,Seconds(5))
    //连接socket服务,需要socket服务地址、端口号以及存储级别(默认的)
    val dstream:ReceiverInputDStream[String] = ssc.socketTextStream("192.168.169.200",9999)
    //通过空格分隔
    val words:DStream[String] = dstream.transform(line => line.flatMap(_.split(" ")))
    //打印输出结果
    words.print()
    //开启流式计算
    ssc.start()
    //用于保护程序正常运行
    ssc.awaitTermination()
  }
}

D、运行程序可以看出,语句I like spark streaming and Hadoop在5s内被分割成6个单词,结果如下图:

(2)、 updateStateByKey(func) 方法

updateStateByKey(func) 方法可以保持任意状态,同时允许不断有新的信息进行更新。 下面举例演示如何使用updateStateByKey(func) 方法进行词频统计: 在项目的/src/main/scala目录下创建包,接着创建一个名为UpdateStateByKeyTest的scala类,主要用于编写SparkStreaming应用程序,实现词频统计,具体代码如下:

package SparkStreaming

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

object UpdateStateByKeyTest {

  def updateFunction(newValues:Seq[Int],runningCount:Option[Int]) : Option[Int] = {
    val newCount = runningCount.getOrElse(0)+newValues.sum
    Some(newCount)
  }
  def main(args: Array[String]): Unit = {
    //创建SparkConf对象
    val sparkconf = new SparkConf().setAppName("UpdateStateByKeyTest").setMaster("local[2]")
    //创建SparkContext对象
    val sc = new SparkContext(sparkconf)
    //设置日志级别
    sc.setLogLevel("WARN")
    //创建StreamingContext,需要创建两个参数,分别为SparkContext和批处理时间间隔
    val ssc = new StreamingContext(sc,Seconds(5))
    //连接socket服务,需要socket服务地址、端口号以及存储级别(默认的)
    val dstream:ReceiverInputDStream[String] = ssc.socketTextStream("192.168.169.200",9999)
    //通过逗号分隔第一个字段和第二个字段
    val words:DStream[(String,Int)] = dstream.flatMap(_.split(" ")).map(word => (word,1))
    //调用updateStateByKey操作
    var result:DStream[(String,Int)] = words.updateStateByKey(updateFunction)
    //如果用到updateStateByKey,此处要加上ssc.checkpoint("目录")这一句,否则会报错:
    // The checkpoint directory has not been set. Please set it by StreamingContext.checkpoint().
    //为什么要用到checkpoint?因为之前的案例是没有状态的,用完之后就丢掉,不需要了,
    // 但是现在要用到之前的那些数据,要把之前的状态保留下来
    //“.”的意思是当前目录
    ssc.checkpoint(".")
    //打印输出结果
    result.print()
    //开启流式计算
    ssc.start()
    //用于保护程序正常运行
    ssc.awaitTermination()
  }
}

然后在9999端口不断输入单词,具体内容如下:

运行程序从控制台输出的结果看出每隔5s接受一次数据,一共接受了两次数据,并且每接受一次数据就会进行词频统计并输出结果。