spark streaming原始碼分析4 DStream相關API

五柳-先生發表於2016-01-29
一、InputDStream建立的操作(StreamingContext.scala)
1、給定Receiver作為引數,建立ReceiverInputDStream,T為receiver接收到的資料型別
[java] view plain copy
  1. def receiverStream[T: ClassTag](receiver: Receiver[T]): ReceiverInputDStream[T] = {  
  2.     withNamedScope("receiver stream") {  
  3.       new PluggableInputDStream[T](this, receiver)  
  4.     }  
  5.   }  
2、根據引數生成akka actorstream接收資料
  1. def actorStream[T: ClassTag](  
  2.       props: Props,  
  3.       name: String,  
  4.       storageLevel: StorageLevel = StorageLevel.MEMORY_AND_DISK_SER_2,  
  5.       supervisorStrategy: SupervisorStrategy = ActorSupervisorStrategy.defaultStrategy  
  6.     ): ReceiverInputDStream[T] = withNamedScope("actor stream") {  
  7.     receiverStream(new ActorReceiver[T](props, name, storageLevel, supervisorStrategy))  
  8.   }  
3、TCP socket
socketStream:converter是從socket輸入流轉換成元素T的迭代器的方法
  1. def socketStream[T: ClassTag](  
  2.       hostname: String,  
  3.       port: Int,  
  4.       converter: (InputStream) => Iterator[T],  
  5.       storageLevel: StorageLevel  
  6.     ): ReceiverInputDStream[T] = {  
  7.     new SocketInputDStream[T](this, hostname, port, converter, storageLevel)  
  8.   }  
socketTextStream:storageLevel預設是MEMORY_AND_DISK_SER_2,converter是從inputstream中按行讀取轉換成迭代器的固定方法
  1. def socketTextStream(  
  2.       hostname: String,  
  3.       port: Int,  
  4.       storageLevel: StorageLevel = StorageLevel.MEMORY_AND_DISK_SER_2  
  5.     ): ReceiverInputDStream[String] = withNamedScope("socket text stream") {  
  6.     socketStream[String](hostname, port, SocketReceiver.bytesToLines, storageLevel)  
  7.   }  
4、fileStream:filter:檔案過濾器,newFileOnly:只讀取新的檔案。還有其他一些使用預設引數的方法。
  1. def fileStream[  
  2.     K: ClassTag,  
  3.     V: ClassTag,  
  4.     F <: NewInputFormat[K, V]: ClassTag  
  5.   ] (directory: String,  
  6.      filter: Path => Boolean,  
  7.      newFilesOnly: Boolean,  
  8.      conf: Configuration): InputDStream[(K, V)] = {  
  9.     new FileInputDStream[K, V, F](this, directory, filter, newFilesOnly, Option(conf))  
  10.   }  
一個以固定格式讀取檔案作為輸入的介面
  1. def textFileStream(directory: String): DStream[String] = withNamedScope("text file stream") {  
  2.     fileStream[LongWritable, Text, TextInputFormat](directory).map(_._2.toString)  
  3.   }  
與receiverInputDStream不同,它是以檔案作為輸入,所以不需要receiver去讀取。而是直接根據path生成hadoopRDD,再將所有的RDD Union起來。也就是說,在一個batchDuration時間間隔內,就將這個間隔內新的file組合成一個RDD。
5、將多個DStream 聯合,返回UnionDStream。compute方法就是將多個DStream中的Rdd union
  1. /** 
  2.    * Create a unified DStream from multiple DStreams of the same type and same slide duration. 
  3.    */  
  4.   def union[T: ClassTag](streams: Seq[DStream[T]]): DStream[T] = withScope {  
  5.     new UnionDStream[T](streams.toArray)  
  6.   }  
6、transform:將dstreams中得到的所有rdds轉換成一個RDD
  1. /** 
  2.    * Create a new DStream in which each RDD is generated by applying a function on RDDs of 
  3.    * the DStreams. 
  4.    */  
  5.   def transform[T: ClassTag](  
  6.       dstreams: Seq[DStream[_]],  
  7.       transformFunc: (Seq[RDD[_]], Time) => RDD[T]  
  8.     ): DStream[T] = withScope {  
  9.     new TransformedDStream[T](dstreams, sparkContext.clean(transformFunc))  
  10.   }  
二、DStream操作(DStream.scala)
與RDD不同的是,DStream是以一個outputStream作為一個job。
那outputStream是如何產生的呢?在呼叫foreachRDD方法時通過註冊將一個DStream在DStreamGraph中標記為outputStream。
那有哪些API會註冊outputStream呢?
foreachRDD/print
saveAsNewAPIHadoopFiles/saveAsTextFiles
1、map/flatMap/filter/mapPartitions
與RDD類似,分別生成MappedDstream/FlatMappedDStream/FilteredDStream等,真正運算時根據receiverInputDStream的compute方法產生BlockRDD,再在這個RDD上賦予map的方法引數執行操作。
2、重新分割槽
方法最終是將BlockRDD進行重新分割槽
  1. /** 
  2.    * Return a new DStream with an increased or decreased level of parallelism. Each RDD in the 
  3.    * returned DStream has exactly numPartitions partitions. 
  4.    */  
  5.   def repartition(numPartitions: Int): DStream[T] = ssc.withScope {  
  6.     this.transform(_.repartition(numPartitions))  
  7.   }  
3、reduce:這個方法將DStream的每個RDD都執行reduceFunc方法,並最終每個RDD只有一個分割槽,返回的還是一個DStream[T]
區別:RDD.scala的reduce方法是提交runJob的,返回一個確切的值。
  1. /** 
  2.    * Return a new DStream in which each RDD has a single element generated by reducing each RDD 
  3.    * of this DStream. 
  4.    */  
  5.   def reduce(reduceFunc: (T, T) => T): DStream[T] = ssc.withScope {  
  6.     this.map(x => (null, x)).reduceByKey(reduceFunc, 1).map(_._2)  
  7.   }  
4、count:這個方法是將DStream中的每個RDD進行計數,返回一個包含技術的DStream
  1. /** 
  2.    * Return a new DStream in which each RDD has a single element generated by counting each RDD 
  3.    * of this DStream. 
  4.    */  
  5.   def count(): DStream[Long] = ssc.withScope {  
  6.     this.map(_ => (null, 1L))  
  7.         .transform(_.union(context.sparkContext.makeRDD(Seq((null, 0L)), 1)))  
  8.         .reduceByKey(_ + _)  
  9.         .map(_._2)  
  10.   }  
5、countByValue:類似count方法,只是該方法是按value值計數的
  1. def countByValue(numPartitions: Int = ssc.sc.defaultParallelism)(implicit ord: Ordering[T] = null)  
  2.       : DStream[(T, Long)] = ssc.withScope {  
  3.     this.map(x => (x, 1L)).reduceByKey((x: Long, y: Long) => x + y, numPartitions)  
  4.   }  
6、foreachRDD:foreachFunc是在一個RDD進行自定義的任何操作
  1. def foreachRDD(foreachFunc: RDD[T] => Unit): Unit = ssc.withScope {  
  2.     val cleanedF = context.sparkContext.clean(foreachFunc, false)  
  3.     this.foreachRDD((r: RDD[T], t: Time) => cleanedF(r))  
  4.   }  
  1. def foreachRDD(foreachFunc: (RDD[T], Time) => Unit): Unit = ssc.withScope {  
  2.     // because the DStream is reachable from the outer object here, and because  
  3.     // DStreams can't be serialized with closures, we can't proactively check  
  4.     // it for serializability and so we pass the optional false to SparkContext.clean  
  5.     new ForEachDStream(this, context.sparkContext.clean(foreachFunc, false)).register()  
  6.   }  
7、transform:在最終生成的RDD上執行transformFunc方法定義的轉換操作
  1. def transform[U: ClassTag](transformFunc: RDD[T] => RDD[U]): DStream[U]  
  1. def transform[U: ClassTag](transformFunc: (RDD[T], Time) => RDD[U]): DStream[U]  
8、transformWith:將自身DStream生成的RDD與other生成的RDD一起,執行transformWith方法。
  1. def transformWith[U: ClassTag, V: ClassTag](  
  2.       other: DStream[U], transformFunc: (RDD[T], RDD[U]) => RDD[V]  
  3.     ): DStream[V]  
  1. def transformWith[U: ClassTag, V: ClassTag](  
  2.       other: DStream[U], transformFunc: (RDD[T], RDD[U], Time) => RDD[V]  
  3.     ): DStream[V]  
9、union聯合
  1. def union(that: DStream[T]): DStream[T] = ssc.withScope {  
  2.     new UnionDStream[T](Array(this, that))  
  3.   }  
10、saveAsObjectFiles/saveAsTextFiles
儲存為檔案
三、K/V型別RDD轉換操作
1、groupByKey
  1. def groupByKey(): DStream[(K, Iterable[V])] = ssc.withScope {  
  2.     groupByKey(defaultPartitioner())  
  3.   }  
  1. def groupByKey(numPartitions: Int): DStream[(K, Iterable[V])] = ssc.withScope {  
  2.     groupByKey(defaultPartitioner(numPartitions))  
  3.   }  
  1. def groupByKey(partitioner: Partitioner): DStream[(K, Iterable[V])] = ssc.withScope {  
  2.     val createCombiner = (v: V) => ArrayBuffer[V](v)  
  3.     val mergeValue = (c: ArrayBuffer[V], v: V) => (c += v)  
  4.     val mergeCombiner = (c1: ArrayBuffer[V], c2: ArrayBuffer[V]) => (c1 ++ c2)  
  5.     combineByKey(createCombiner, mergeValue, mergeCombiner, partitioner)  
  6.       .asInstanceOf[DStream[(K, Iterable[V])]]  
  7.   }  
2、reduceByKey
  1. def reduceByKey(reduceFunc: (V, V) => V): DStream[(K, V)]  
  1. def reduceByKey(  
  2.       reduceFunc: (V, V) => V,  
  3.       numPartitions: Int): DStream[(K, V)]  
  1. def reduceByKey(  
  2.       reduceFunc: (V, V) => V,  
  3.       partitioner: Partitioner): DStream[(K, V)]  
3、combineByKey
  1. def combineByKey[C: ClassTag](  
  2.       createCombiner: V => C,  
  3.       mergeValue: (C, V) => C,  
  4.       mergeCombiner: (C, C) => C,  
  5.       partitioner: Partitioner,  
  6.       mapSideCombine: Boolean = true): DStream[(K, C)] = ssc.withScope {  
  7.     val cleanedCreateCombiner = sparkContext.clean(createCombiner)  
  8.     val cleanedMergeValue = sparkContext.clean(mergeValue)  
  9.     val cleanedMergeCombiner = sparkContext.clean(mergeCombiner)  
  10.     new ShuffledDStream[K, V, C](  
  11.       self,  
  12.       cleanedCreateCombiner,  
  13.       cleanedMergeValue,  
  14.       cleanedMergeCombiner,  
  15.       partitioner,  
  16.       mapSideCombine)  
  17.   }  
4、mapValues/flatMapValues與RDD的操作類似,不解釋
5、join
內部呼叫transformWith,transformWith的引數就是將兩個引數RDD作join操作。
  1. def join[W: ClassTag](  
  2.       other: DStream[(K, W)],  
  3.       partitioner: Partitioner  
  4.     ): DStream[(K, (V, W))] = ssc.withScope {  
  5.     self.transformWith(  
  6.       other,  
  7.       (rdd1: RDD[(K, V)], rdd2: RDD[(K, W)]) => rdd1.join(rdd2, partitioner)  
  8.     )  
  9.   }  
6、saveAsNewAPIHadoopFiles

儲存到檔案

轉載: http://blog.csdn.net/yueqian_zhu/article/details/49121489

相關文章