Githup项目LearningSpark代码讲解(八)

package streaming

import java.io.File

import org.apache.spark.streaming._
import org.apache.spark.{SparkConf, SparkContext}
import streaming.util.CSVFileStreamGenerator

import scala.util.Random


//
// File based streaming requires files to be atomically created in
// the source directory -- in practice this entails creating them somewhere
// else and renaming them in place. Every batch emitted by the StreamingContext
// produces all the data from all files that have appeared since the last
// batch -- potentially many files are combined into a single RDD each time.
//

/**
  * 这个方法就是定时写文件,然后让spark去读
  */
object FileBasedStreaming {
  def main (args: Array[String]) {
    val conf = new SparkConf().setAppName("FileBasedStreaming").setMaster("local[4]")
    val sc = new SparkContext(conf)

    // streams will produce data every second
    val ssc = new StreamingContext(sc, Seconds(1))
    val fm = new CSVFileStreamGenerator(10, 100, 500)

    // create the stream
    /**
      * 这里面需要注意的是textFileStream返回的是DStream
      * 那么DStream和RDD的区别是什么
      *
      * 离散流(DStream)是Spark Streaming中的基本抽象,是表示连续数据流的连续RDD序列(相同类型)(
      * 请参阅Spark核心文档中的org.apache.spark.rdd.RDD以获取更多信息)有关RDD的详细信息)。
      * 可以使用[[org.apache.spark.streaming.StreamingContext]]从实时数据(例如来自TCP套接字,Kafka,Flume等的数据)创建DStream,
      * 也可以通过使用操作转换现有DStream来生成DStreams例如`map`,`window`和`reduceByKeyAndWindow`。当Spark Streaming程序正在运行时,
      * 每个DStream都会定期生成RDD,可以是实时数据,也可以是转换父DStream生成的RDD。
      *
      * 该类包含所有DStream上可用的基本操作,例如`map`,`filter`和`window`。
      * 此外,[[org.apache.spark.streaming.dstream.PairDStreamFunctions]]包含仅在键值对的DStream上可用的操作,
      * 例如`groupByKeyAndWindow`和`join`。通过隐式转换,这些操作在任何DStream对(例如,DStream [(Int,Int)]上自动可用。
      *
      * 内部的DStream具有一些基本属性:
      *    -  DStream依赖的其他DStream列表
      *    -  DStream生成RDD的时间间隔
      *    - 用于在每个时间间隔后生成RDD的函数
      *
      *
      * 可以通过DStream的源代码发现slideDuration这个方法是一个RDD的周期,而在实现类中
      * override def slideDuration: Duration = {
      *   if (ssc == null) throw new Exception("ssc is null")
      *   if (ssc.graph.batchDuration == null) throw new Exception("batchDuration is null")
      *       ssc.graph.batchDuration
      *  }
      *  他返回的就是ssc.graph.batchDuration,而ssc.graph.batchDuration指的就是newGraph.setBatchDuration(_batchDur)
      *  _batchDur指代的val ssc = new StreamingContext(sc, Seconds(1))中Seconds(1),所以在Stream中一个RDD就是 Seconds(1)
      *  中时间段接受的数据
      *
      *
      * DStream有两个window函数,用来创建窗口。每个窗口有两个变量:窗口大小和滑动周期。在第一个函数中,窗口大小通过参数指定,
      * 滑动周期来自于调用函数的DStream(如果这个DStream是由StreamingContext直接创建的,那么滑动周期刚好等于批处理周期)。
      * 在第二个函数中,窗口大小和滑动周期都是通过函数指定。
      *
      * 然而,在WindowedDStream中,它的slideDuration函数返回的是这个窗口的滑动周期。也就是说,每个滑动窗口才对应着一个RDD,
      * 而不是一个批处理周期对应一个RDD。
      *
      * 逻辑可以很复杂,也可以很简单,最终二者是可以统一的:
      * 1. 所有的DStream都可以看作是WindowedDStream
      * 2. 每个窗口都有窗口大小和滑动周期
      * 3. StreamingContext直接创建的窗口,可以叫做基本窗口,它的窗口大小和滑动周期与批处理周期相同
      *
      *
      *
      */
    val stream = ssc.textFileStream(fm.dest.getAbsolutePath)

    // register for data
    stream.foreachRDD(r => {
      println(r.count())
    })

    // start streaming
    ssc.start()

    new Thread("Streaming Termination Monitor") {
      override def run() {
        try {
          ssc.awaitTermination()
        } catch {
          case e: Exception => {
            println("*** streaming exception caught in monitor thread")
            e.printStackTrace()
          }
        }
        println("*** streaming terminated")
      }
    }.start()

    println("*** started termination monitor")

    // A curious fact about files based streaming is that any files written
    // before the first RDD is produced are ignored. So wait longer than
    // that before producing files.
    Thread.sleep(2000)
    println("*** producing data")
    // start producing files
    fm.makeFiles()

    Thread.sleep(10000)

    println("*** stopping streaming")
    ssc.stop()

    // wait a bit longer for the call to awaitTermination() to return
    Thread.sleep(5000)

    println("*** done")
  }
}

你可能感兴趣的:(Spark)