:元、転送先アドレスを指定してくださいhttps://www.cnblogs.com/dongxiao-yang/p/11358781.htmlを
ベースのスパークソースのバージョンは2.4.3です
典型的には、需要状態計算、すなわち、そこになり、現在だけでなく、電流の流れに対する計算の計算結果にミニバッチsparkstreaming機構ので、結果前の状態をに格納する必要があり、その結果は、以前に必要な計算されたシーンデータを受信組み合わせに依存しますRDDと有用updateStateByKey方法でマージを除去するために次のバッチを計算します。
シンプルなユースケース:
DEFメイン(引数:配列[文字列]):単位= { ヴァルホスト= "localhost"を ヴァルポート= "8001" StreamingExamples.setStreamingLogLevelsは() // 1秒バッチサイズを有するコンテキストを作成 ヴァルsparkConf =新しいSparkConfを()。 setMaster( "ローカル[4]")。setAppName( "NetworkWordCount") ヴァルSSC =新しいStreamingContext(sparkConf、秒(10)) ssc.checkpoint( "/ユーザ/ dyang /デスクトップ/ checkpoittmp") ヴァルライン= ssc.socketTextStream (ホスト、port.toInt、StorageLevel.MEMORY_AND_DISK_SER) ヴァルワード= lines.flatMap(_スプリット(」「)。) ヴァルwordCounts:DSTREAM [(文字列、INT)] = words.map(X =>(X、1) )
//.reduceByKey(_ + _) ヴァルtotalCounts = wordCounts.updateStateByKey {(値:配列[INT]、状態:オプション[INT])=>一部(values.sum + state.getOrElse(0))} totalCounts.print() ssc.start() SSC。 awaitTermination() }
上記の例では、状態の統計情報を持っている語数の簡単なバージョンを示し、updateStateByKeyの役割で、アプリケーションは次の和の到着と蓄積されたデータの前にすべての単語の数を覚えています。
異なるパラメータを持つupdateStateByKeyパッケージ版、次のように定義された全体の比較
/ ** *各キーの状態を適用することにより更新され、新たな「状態」DSTREAM戻る キーと、各キーの新しい値を以前の状態に*与えられた関数を。 *すべてのバッチでupdateFuncは、新しい値がない場合でも、それぞれの状態のために呼び出されます。 * [[org.apache.spark.Partitioner]各RDDの分配を制御するために使用されます。 * @param updateFunc状態更新機能。この関数は異なる生成してもよいことに、注意 入力キーとは異なるキーを持つ*タプル。したがって、キーは削除されてもよい *またはこのようにして加えました。これは、するかどうかを決定するために、開発者に任されて *キーが変更されているにもかかわらずパーティを覚えています。 新しい各RDDのパーティショニングを制御する* @paramのパーティパーティショナ * DSTREAM 生成RDDSにパーティショナオブジェクトを覚えているかどうか* @param rememberPartitioner。 * @tparam Sステート型 * / DEF updateStateByKey [S:ClassTag( updateFunc:(イテレータ[(K、配列[V]、オプションの[S])])=>イテレータ[(K、S)]、 パーティショナ:パーティショナ、 rememberPartitioner:ブール値):DSTREAM [(K、S)= ssc.withScope { ヴァルcleanedFunc = ssc.sc.clean(updateFunc) ヴァルnewUpdateFunc =(_:時間、それは:イテレータ[(K、配列[V]、オプションの[S])])=> { cleanedFunc(IT) } 新しいStateDStream(自己、newUpdateFunc、パーティ、rememberPartitioner、なし) }
元のユーザーupdateFuncでパラメータが関数に渡されており、updateFunc(配列[V]、オプションの[S])=>オプション[S]は変換です。
ヴァルcleanedUpdateF(配列[V]、オプションの[S])=>オプション[S] = sparkContext.clean(updateFunc) ヴァルnewUpdateFunc =(イテレータ:イテレータ[(K、配列[V]、オプションの[S])]) => { iterator.flatMap(T => { cleanedUpdateF(t._2、t._3).MAP(S =>(t._1、S)) }) } updateStateByKey(newUpdateFunc、パーティショナ、真)
最終結果はStateDStreamに変換updateStateByKeyのPairDStreamFunctionsあります。すべてのDSTREAMについては、compute(time)方法都是他们生成每个duration RDD的具体实现
DEF計算オーバーライド(validTime:時間):オプション[RDD [(K、S)]] = { //前の状態RDD取得しよう getOrCompute(validTime - slideDuration)マッチ{ ケースの一部(prevStateRDD)=> //前の場合を状態RDDは存在 //親RDD取得してください parent.getOrCompute(validTime)試合{ 場合、一部(parentRDD)=> //親RDDが存在する場合は、いつものように計算 computeUsingPreviousRDD(validTime、parentRDD、prevStateRDD) なし=> /ケース/親RDDが存在しない場合は 、古い状態に//再適用する更新機能をRDD ヴァルupdateFuncLocal = updateFunc ヴァルfinalFunc =(イテレータ:イテレータ[(K、S)])=> { I = iterator.map(T =>(t._1、Seq.empty [V]、オプション(t._2)))ヴァル updateFuncLocal(validTime、I) } ヴァルstateRDD = prevStateRDD.mapPartitions(finalFunc、preservePartitioning) の一部( stateRDD) } 前回RDDは、(第1の入力データ)が存在しない場合はケースなし=>は// 親RDD取得しよう// parent.getOrCompute(validTime)一致{ ケースの一部(parentRDDを)=>親RDDは存在しない//場合、その後、通常通り計算 initialRDD一致{ ケースなし=> //グループ化されたRDDにmapPartition動作のための機能を定義します。 //まず、必要なタイプの組にグループ化されたタプルのマッピング いくつかの(sessionRDD) // [更新関数を適用 ヴァルupdateFuncLocal = updateFunc ヴァルfinalFunc =(イテレータ:イテレータ[(K、反復処理可能[V])])=> { updateFuncLocal(validTime、 iterator.map(タプル=>(tuple._1、タプル._2.toSeq、なし))) } ヴァルgroupedRDD = parentRDD.groupByKey(パーティ) ヴァルsessionRDD = groupedRDD.mapPartitions(finalFunc、preservePartitioning) // logDebug( "時間状態RDDの生成" + validTime + "(最初の)") ケースのいくつか(initialStateRDD)=> computeUsingPreviousRDD(validTime、parentRDD、initialStateRDD) } ケースなし=> //親RDDが存在しない場合は、何も行わないために! // logDebug( "状態RDD(なし以前の状態、ノー親)を生成しない") なし } } }
それは親の意味を説明しなければならない:本親さ DStream
依存の上流側 DStream,从上面
には、PairDStreamFunctions DSTREAM自体はDSTREAM間着信DAG関係を通過するように構成されて生成された自己最後見updateStateByKey StateDstreamインスタンス化コードです。
DSTREAM介して各内部HashMapの[ 時間、RDD [ T]()は、キーRDDのリストを管理するために生成された Time
ことは、 Time
ユーザによって指定された batchDuration
-例えば毎15Sは、単語のバッチを生成するために、整列時間その鍵は、ここでの時間で 08h:00m:00s
、08h:00m:15s
実際には、それはまた、いくつかのバッチの最初表し、。generatedRDD
値である RDD
例は、そう parent.getOrComputeは(validTime)はこの呼び出しは、上流DSTREAMを通じて取得した後、対応する転送動作を生成RDDを表します。
computeUsingPreviousRDD:上記ソースは、非常に詳細なメモをもたらし、様々なparentRDD /(prevStateRDD / initialRDD)不完全な境界を除外した後、この方法は、方法の現在および過去の状態をマージに進みます
プライベート【この】DEF computeUsingPreviousRDD( batchTime:時間、 parentRDD:RDD [(K、V)]、 prevStateRDD:RDD [(K、S)])= { // cogrouped RDDにmapPartition動作のための機能を定義します。 //まず、必要なタイプのタプルにcogroupedタプルをマッピング // [更新関数を適用 ヴァルupdateFuncLocal = updateFunc ヴァルfinalFunc =(イテレータ:イテレータ[(K、(反復処理可能[V]、反復処理可能[S]))]) => { ヴァルI = iterator.map {T => ヴァルITR = t._2._2.iterator ヴァルheadOption = IF(itr.hasNext)の一部(itr.next())他なし (t._1、t._2 ._1.toSeq、headOption) } updateFuncLocal(batchTime、I) } 選択cogroupedRDD = parentRDD.cogroup(prevStateRDD、パーティション) 選択stateRDD = cogroupedRDD.mapPartitions(finalFunc、preservePartitioning) の一部(stateRDD) }
この方法は第一の電流データparentRDDとprevStateRDDはコグループ操作た、戻り値のデータ型は、KはDSTREAMのキーの種類、値型であるRDD [(K、(反復処理可能を[V]、反復処理可能[S]))]、ビット現在の反復処理可能terable [V]と過去の状態データ[S])バイナリタプル、上記式火花updateFuncのパラメータを一致させるために:(イテレータを[(K、配列[V]、オプションの[S])])パッケージを続行
ヴァルfinalFunc =(イテレータ:イテレータ[(K、(反復処理可能[V]、反復処理可能[S]))])
逆にそれが(K、(反復処理可能[V]、反復処理可能[S]))最初のカプセル化されたデータRDDがなった後(イテレータ[(K、配列[V]、オプションの[S])]フォーマットの形で最初でありますそして、ユーザ定義関数updateFuncの状態と第二のパッケージに付す(配列[V]、オプションの[S])=>オプション[S]コールとRDD [(K、S)]の形式RDDを返します。
注意:
暗黙的な変換スパーク源の多数は、そのような方法は、DSTREAM updateStateByKeyに存在しないが、PairDStreamFunctions、オブジェクト、関連するオブジェクトに起因しているDSTREAM暗黙的な変換であります
暗黙DEF toPairDStreamFunctions [K、V](ストリーム:DSTREAM [(K、V)]) (暗黙KT:ClassTag [K]、VT:ClassTag [V]、ORD:注文[K] = NULL): PairDStreamFunctions [K、 V = { 新しいPairDStreamFunctions [K、V](ストリーム) }
すべての適格DSTREAM [(K、V)は、この暗黙の変換アダプタを介してオブジェクトPairDStreamFunctionsにキーと値のタイプであります
チェックポイント機能を開かなければならない状態の演算子を使用する場合は2は、プログラムがチェックすることにより、エラー状態を開始することができません。
java.lang.IllegalArgumentExceptionが:要求に失敗しました:チェックポイントのディレクトリが設定されていません。StreamingContext.checkpoint(でそれを設定してください)
参考文献:
1つの DSTREAM例示説明発生RDD