DStream编程数据模型

DStream(Discretized Stream)作为Spark Streaming的基础抽象,它代表持续性的数据流。

这些数据流既可以通过外部输入源赖获取,也可以通过现有的Dstream的transformation操作来获得。

在内部实现上,DStream由一组时间序列上连续的RDD来表示。每个RDD都包含了自己特定时间间隔内的数据流。

对DStream中数据的各种操作也是映射到内部的RDD上来进行的

对Dtream的操作可以通过RDD的transformation生成新的DStream。

我们把RDD加上一个时间属性来区分。

我们可以把DStream当作一连串用时间分段的RDD来看待,并且这串是RDD像流水一样绵绵不断的。

当我们对DStream采取一些操作的时候,其中每段时间的RDD之间相互对应转化成新的DStream.

SparkStreaming的基本步骤

1.通过创建输入DStream来定义输入源

2.通过对DStream应用转换操作和输出操作来定义流计算,用户自己定义处理逻辑

3.通过streamingContext.start()来开始接收数据和处理流程

4.通过streamingContext.awaitTermination()方法来等待处理结果

5.通过streamingContext.stop()来手动结束流计算流程

具体步骤

1.创建StreamingContext对象

(1)通过 new StreamingContext(SparkConf,Interval)建立

  创建StreamingContext对象所需的参数有两个一个是 SparkConf 配置参数,一个是时间参数。

  与SparkContext基本一致,SparkConf 配置参数需要指明Master,任务名称(如NetworkWordCount)。

  时间参数我们如果以秒来定义的话格式为Seconds(n),这个参数定义了Spark Streaming需要指定处理数据的时间间隔,

  时间参数需要根据用户的需求和集群的处理能力进行适当的设置。

  例如

val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
val ssc = new StreamingContext(conf, Seconds(1))

  这里的那么Spark Streaming会以1s为时间窗口进行数据处理。

(2)通过 new StreamingContext(SparkContext,Interval)建立

val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
val sc = new SparkContext(conf)
val ssc = new StreamingContext(sc, Seconds(1))

这种方式一般用于spark-shell中建立,

spark-shell中给我们定义好了sc,但是spark-shell并没有为我们建立好ssc

所以我们需要自己建立ssc

在建立ssc 之前我们需要导入 import org.apache.spark.streaming._ 

在编码之前我们需要设置一下日志等级,以便我们之后的程序调试。

要么日志会把所有东西都显示出来,你根本找不到哪条是错误信息。

//设置日志等级的单例对象
import org.apache.log4j.{Logger,Level}
import org.apache.spark.internal.Logging
object StreamingLoggingExample extends Logging{
def setStreamingLogLevels(): Unit ={
val log4jInitialized = Logger.getRootLogger.getAllAppenders.hasMoreElements
if(!log4jInitialized)
logInfo("Setting log level to [WARN] for streaming example" +
"To override add a custom log4j.properties to the classpath"
)
Logger.getRootLogger.setLevel(Level.WARN)
}
} //使用单例对象修改日志等级
StreamingLoggingExample.setsetStreamingLogLevels()
//注意在编码之前设置

2.创建InputDStream

 我们通过设置InputDStream来设置数据的来源

 Spark Streaming支持的数据源有文件流、套接字流、RDD队列流、Kafka、 Flume、HDFS/S3、Kinesis和Twitter等数据源。

(1)文件流 

val lines = ssc.textFileStream("file:///")

  文件流的加载的是系统中的文件,可以是HDFS中的也可以是本地的,跟创建RDD是一样的。

(2)套接字流

val lines = ssc.socketTextStream("hostname", port.toInt) 

(3)RDD队列流

创建RDD队列

val rddQueue = new scala.collection.mutable.SynchronizedQueue[RDD[Int]]()//建立一个整型RDD的队列流,初始化为空

创建RDD队列流的spark流进行监听

val lines = ssc.queueStream(rddQueue)

rdd队列流中添加数据

for(i <- 1 to 100){
rddQueue += ssc.sparkContext.makeRDD(1 to 100,2) //添加数据到RDD队列
}

(4)Kafka

3.操作DStream

  对于从数据源得到的DStream,用户可以在其基础上进行各种操作。

  与RDD类似,DStream也提供了自己的一系列操作方法,这些操作可以分成三类:普通的转换操作、窗口转换操作和输出操作。

(1)普通的转换操作

转换

描述

map(func)

源 DStream的每个元素通过函数func返回一个新的DStream。

flatMap(func)

类似与map操作,不同的是每个输入元素可以被映射出0或者更多的输出元素。

filter(func)

在源DSTREAM上选择Func函数返回仅为true的元素,最终返回一个新的DSTREAM 。

repartition(numPartitions)

通过输入的参数numPartitions的值来改变DStream的分区大小。

union(otherStream)

返回一个包含源DStream与其他 DStream的元素合并后的新DSTREAM。

count()

对源DStream内部的所含有的RDD的元素数量进行计数,返回一个内部的RDD只包含一个元素的DStreaam。

reduce(func)

使用函数func(有两个参数并返回一个结果)将源DStream 中每个RDD的元素进行聚 合操作,返回一个内部所包含的RDD只有一个元素的新DStream。

countByValue()

计算DStream中每个RDD内的元素出现的频次并返回新的DStream[(K,Long)],其中K是RDD中元素的类型,Long是元素出现的频次。

reduceByKey(func, [numTasks])

当一个类型为(K,V)键值对的DStream被调用的时候,返回类型为类型为(K,V)键值对的新 DStream,其中每个键的值V都是使用聚合函数func汇总。注意:默认情况下,使用 Spark的默认并行度提交任务(本地模式下并行度为2,集群模式下位8),可以通过配置numTasks设置不同的并行任务数。

join(otherStream, [numTasks])

当被调用类型分别为(K,V)和(K,W)键值对的2个DStream 时,返回类型为(K,(V,W))键值对的一个新 DSTREAM。

cogroup(otherStream, [numTasks])

当被调用的两个DStream分别含有(K, V) 和(K, W)键值对时,返回一个(K, Seq[V], Seq[W])类型的新的DStream。

transform(func)

通过对源DStream的每RDD应用RDD-to-RDD函数返回一个新的DStream,这可以用来在DStream做任意RDD操作。

updateStateByKey(func)

返回一个新状态的DStream,其中每个键的状态是根据键的前一个状态和键的新值应用给定函数func后的更新。这个方法可以被用来维持每个键的任何状态数据。

注意:

transform(func)

  该transform操作(转换操作)连同其其类似的 transformWith操作允许DStream 上应用任意RDD-to-RDD函数。

  它可以被应用于未在 DStream API 中暴露任何的RDD操作。

  例如,在每批次的数据流与另一数据集的连接功能不直接暴露在DStream API 中,但可以轻松地使用transform操作来做到这一点,这使得DStream的功能非常强大。

  例如,你可以通过连接预先计算的垃圾邮件信息的输入数据流(可能也有Spark生成的),然后基于此做实时数据清理的筛选,如下面官方提供的伪代码所示。

  事实上,也可以在transform方法中使用机器学习和图形计算的算法。

val spamInfoRDD = ssc.sparkContext.newAPIHadoopRDD(...) // RDD containing spam information

val cleanedDStream = wordCounts.transform { rdd =>
rdd.join(spamInfoRDD).filter(...) // join data stream with spam information to do data cleaning
...
}

updateStateByKey操作

  我们使用的一般操作都是不记录历史数据的,也就说只记录当前定义时间段内的数据,跟前后时间段无关。

  如果我们想统计历史时间内的总共数据并且实时更新呢?

  该 updateStateByKey 操作可以让你保持任意状态,同时不断有新的信息进行更新。要使用此功能,必须进行两个步骤 :

  (1)  定义状态 - 状态可以是任意的数据类型。

  (2)  定义状态更新函数 - 用一个函数指定如何使用先前的状态和从输入流中获取的新值 更新状态。

   对DStream通过updateStateByKey(updateFunction)来实现实时更新。

   更新函数有两个参数  1.newValues 是当前新进入的数据  2.runningCount 是历史数据,被封装到了Option中。

   为什么历史数据要封装到Option中呢?有可能我们没有历史数据,这个时候就可以用None,有数据可以用Some(x)。

   当然我们的当前结果也要封装到Some()中,以便作为之后的历史数据。

   我们并不用关心新进入的数据和历史数据,系统会自动帮我们产生和维护,我们只需要专心写处理方法就行。

def updateFunction(newValues: Seq[Int], runningCount: Option[Int]): Option[Int] = {//定义的更新函数
val newCount = ... // add the new values with the previous running count to get the new count
Some(newCount)
}
val runningCounts = pairs.updateStateByKey[Int](updateFunction)//应用

示例:

(1)首先我们需要了解数据的类型

(2)编写处理方法

(3)封装结果

//定义更新函数
//我们这里使用的Int类型的数据,因为要做统计个数
def updateFunc(newValues : Seq[Int],state :Option[Int]) :Some[Int] = {
//传入的newVaules将当前的时间段的数据全部保存到Seq中
//调用foldLeft(0)(_+_) 从0位置开始累加到结束
val currentCount = newValues.foldLeft(0)(_+_)
//获取历史值,没有历史数据时为None,有数据的时候为Some
//getOrElse(x)方法,如果获取值为None则用x代替
val previousCount = state.getOrElse(0)
//计算结果,封装成Some返回
Some(currentCount+previousCount)
}
//使用
val stateDStream = DStream.updateStateByKey[Int](updateFunc) 

(2)窗口转换函数

Spark Streaming 还提供了窗口的计算,它允许你通过滑动窗口对数据进行转换,窗口转换操作如下:

转换

描述

window(windowLength, slideInterval)

返回一个基于源DStream的窗口批次计算后得到新的DStream。

countByWindow(windowLength,slideInterval)

返回基于滑动窗口的DStream中的元素的数量。

reduceByWindow(func, windowLength,slideInterval)

基于滑动窗口对源DStream中的元素进行聚合操作,得到一个新的DStream。

reduceByKeyAndWindow(func,windowLength, slideInterval, [numTasks])

基于滑动窗口对(K,V)键值对类型的DStream中的值按K使用聚合函数func进行聚合操作,得到一个新的DStream。

reduceByKeyAndWindow(func, invFunc,windowLength, slideInterval, [numTasks])

一个更高效的reduceByKkeyAndWindow()的实现版本,先对滑动窗口中新的时间间隔内数据增量聚合并移去最早的与新增数据量的时间间隔内的数据统计量。例如,计算t+4秒这个时刻过去5秒窗口的WordCount,那么我们可以将t+3时刻过去5秒的统计量加上[t+3,t+4]的统计量,在减去[t-2,t-1]的统计量,这种方法可以复用中间三秒的统计量,提高统计的效率。

countByValueAndWindow(windowLength,slideInterval, [numTasks])

基于滑动窗口计算源DStream中每个RDD内每个元素出现的频次并返回DStream[(K,Long)],其中K是RDD中元素的类型,Long是元素频次。与countByValue一样,reduce任务的数量可以通过一个可选参数进行配置。

在Spark Streaming中,数据处理是按批进行的,而数据采集是逐条进行的。

因此在Spark Streaming中会先设置好批处理间隔(batch duration),当超过批处理间隔的时候就会把采集到的数据汇总起来成为一批数据交给系统去处理。

对于窗口操作而言,在其窗口内部会有N个批处理数据,批处理数据的大小由窗口间隔(window duration)决定

而窗口间隔指的就是窗口的持续时间,在窗口操作中,只有窗口的长度满足了才会触发批数据的处理。

除了窗口的长度,窗口操作还有另一个重要的参数就是滑动间隔(slide duration)

它指的是经过多长时间窗口滑动一次形成新的窗口,滑动窗口默认情况下和批次间隔的相同,而窗口间隔一般设置的要比它们两个大。

在这里必须注意的一点是滑动间隔和窗口间隔的大小一定得设置为批处理间隔的整数倍。

如图所示,批处理间隔是1个时间单位,窗口间隔是3个时间单位,滑动间隔是2个时间单位。

对于初始的窗口time 1-time 3,只有窗口间隔满足了定义的长度也就是3才触发数据的处理,不够3继续等待。

当间隔满足3之后进行计算后然后进行窗口滑动,滑动2个单位,会有新的数据流入窗口。

然后重复等待满足窗口间隔执行计算。

(3)输出操作

  Spark Streaming允许DStream的数据被输出到外部系统,如数据库或文件系统。

  由于输出操作实际上使transformation操作后的数据可以通过外部系统被使用,同时输出操作触发所有DStream的transformation操作的实际执行(类似于RDD操作)。

  以下表列出了目前主要的输出操作:

转换

描述

print()

在Driver中打印出DStream中数据的前10个元素。

saveAsTextFiles(prefix, [suffix])

将DStream中的内容以文本的形式保存为文本文件,其中每次批处理间隔内产生的文件以prefix-TIME_IN_MS[.suffix]的方式命名。

saveAsObjectFiles(prefix, [suffix])

将DStream中的内容按对象序列化并且以SequenceFile的格式保存。其中每次批处理间隔内产生的文件以prefix-TIME_IN_MS[.suffix]的方式命名。

saveAsHadoopFiles(prefix, [suffix])

将DStream中的内容以文本的形式保存为Hadoop文件,其中每次批处理间隔内产生的文件以prefix-TIME_IN_MS[.suffix]的方式命名。

foreachRDD(func)

最基本的输出操作,将func函数应用于DStream中的RDD上,这个操作会输出数据到外部系统,比如保存RDD到文件或者网络数据库等。需要注意的是func函数是在运行该streaming应用的Driver进程里执行的。

同样DStream也支持持久化

  与RDD一样,DStream同样也能通过persist()方法将数据流存放在内存中,

4.启动Spark Streaming

  通过streamingContext.start()来开始接收数据和处理流程

  通过streamingContext.awaitTermination()方法来等待处理结果

  通过streamingContext.stop()来手动结束流计算流程

示例

package SparkDemo

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext} object StreamWordCount {
def main(args:Array[String]): Unit ={
//创建StreamingContext
val conf = new SparkConf().setMaster("local[*]").setAppName("StreamTest")
val ssc = new StreamingContext(conf,Seconds(20))
//建立文件流数据源通道
val lines = ssc.textFileStream("file:///")
lines.cache()//持久化
//处理,word count
val words = lines.flatMap(_.split(" "))
val wordPair = words.map((_,1))
val count = wordPair.reduceByKey(_+_)
count.print()
//启动StreamingContext
ssc.start()
ssc.awaitTermination()
} }

然后我们将程序打包提交到spark集群中运行

当程序运行ssc.start()后,就开始自动循环进入监听状态,屏幕上会显示

这是正确的,如果我们在建立ssc的文件中再添加一个文件file3.txt

就可以在监听窗口中显示词频的统计了。

最后我们可以通过ssc.stop()停止程序,不过注意我们不能省略这里的圆括号。

【sparkStreaming】SparkStream的创建的更多相关文章

  1. 【Spark】SparkStreaming与flume进行整合

    文章目录 注意事项 SparkStreaming从flume中poll数据 步骤 一.开发flume配置文件 二.启动flume 三.开发sparkStreaming代码 1.创建maven工程,导入 ...

  2. Spark Streaming流式处理

    Spark Streaming介绍 Spark Streaming概述 Spark Streaming makes it easy to build scalable fault-tolerant s ...

  3. Scala创建SparkStreaming获取Kafka数据代码过程

    正文 首先打开spark官网,找一个自己用版本我选的是1.6.3的,然后进入SparkStreaming   ,通过搜索这个位置找到Kafka, 点击过去会找到一段Scala的代码 import or ...

  4. 【大数据】SparkStreaming学习笔记

    第1章 Spark Streaming概述 1.1 Spark Streaming是什么 Spark Streaming用于流式数据的处理.Spark Streaming支持的数据输入源很多,例如:K ...

  5. 大数据-SparkStreaming

    SparkStreaming SparkStreaming是一种微批处理,准实时的流式框架.数据来源包括:Kafka, Flume,TCP sockets,Twitter,ZeroMQ等 SparkS ...

  6. SparkStreaming 笔记

    简介 SparkStreaming是流式处理框架,是Spark API的扩展,支持可扩展.高吞吐量.容错的准实时数据流处理. 实时数据的来源可以是:Kafka, Flume, Twitter, Zer ...

  7. Spark(十六)【SparkStreaming基本使用】

    目录 一. SparkStreaming简介 1. 相关术语 2. SparkStreaming概念 3. SparkStreaming架构 4. 背压机制 二. Dstream入门 1. WordC ...

  8. SparkStreaming(源码阅读十二)

    要完整去学习spark源码是一件非常不容易的事情,但是咱可以积少成多嘛~那么,Spark Streaming是怎么搞的呢? 本质上,SparkStreaming接收实时输入数据流并将它们按批次划分,然 ...

  9. sparkStreaming与Kafka整合

    createStream那几个参数折腾了我好久..网上都是一带而过,最终才搞懂..关于sparkStreaming的还是太少,最终尝试成功... 首先启动zookeeper ./bin/zookeep ...

随机推荐

  1. 一.数据库连接对象connection

    1.python 3.5,需要把MySQLdb换成pymysql

  2. for and range()

    pyhon 中 for 循环可以遍历任何序列的项目,如一个字典或者一个字符. for 循环格式一般如下: for <variable-变量> in <sequence-序列>: ...

  3. HDU3552(贪心)

    题目是将一系列点对(a,b)分成两个集合.使得A集合的最大a+B集合的最大数b得和最小. 思路:http://blog.csdn.net/dgq8211/article/details/7748078 ...

  4. excel数据生成sql insert语句

    excel表格中有A.B.C三列数据,希望导入到数据库users表中,对应的字段分别是name,sex,age . 在你的excel表格中增加一列,利用excel的公式自动生成sql语句,方法如下: ...

  5. if 条件判断

    逻辑判断的布尔值(true&false) 1.逻辑值(bool)用来表示诸如:对与错,真与假,非于空等概念. 2.逻辑值包含了两个值:--true:表示非空的量(比如:string,tuple ...

  6. unittest 单元测试框架断言方法

    unittest单元测试框架的TestCase类下,测试结果断言方法:Assertion methods 方法 检查 版本 assertEqual(a, b)  a == b assertNotEqu ...

  7. day4-迭代器、生成器yield

    一.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...

  8. 查询前几条记录 top limit

    SQL Server 数据库中的Top关键字可实现查询数据库表中的前几条数据,但是需要注意的是,Top关键字只能在SQL Server数据库中可以使用,而在MySQL数据库中就要使用具有同样功能的LI ...

  9. EOJ - 3631 Delivery Service 2018.8华师大月赛(树链剖分+贪心)

    链接:https://acm.ecnu.edu.cn/contest/103/problem/D/ 题意:给你一棵无向边连接的树,边的权值可以任意互换.有m次运输,每次的花费是点u到v路径上边的权值和 ...

  10. HDU - 3605 Escape (缩点+最大流/二分图多重匹配)

    题意:有N(1<=N<=1e5)个人要移民到M(1<=M<=10)个星球上,每个人有自己想去的星球,每个星球有最大承载人数.问这N个人能否移民成功. 分析:可以用最大流的思路求 ...