2023_Spark_Experiment 11: RDD の高度なオペレーター操作


//checkpoint :

sc.setCheckpointDir("hdfs://Master:9000/ck") // 设置检查点

val rdd = sc.textFile("hdfs://Master:9000/input/word.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_) // 执行wordcount任务的转换



rdd.checkpoint // Mark this RDD for checkpointing.

rdd.isCheckpointed

rdd.count //触发计算,日志显示:ReliableRDDCheckpointData: Done checkpointing RDD 27 to hdfs://hadoop001:9000/ck/fce48fd4-d76f-

4322-8d23-6a48d1aed7b5/rdd-27, new parent is RDD 28

rdd.isCheckpointed // res61: Boolean = true

rdd.getCheckpointFile // Option[String] = Some(hdfs://Master:9000/ck/b9a5add8-18d8-4056-9e8e-271d9522a29c/rdd-4)

合体:

皆さんが知っているように、Spark の RDD プログラミングでは 2 つのオペレーターが再分割および合体します。公開情報によると、どちらもSparkパーティションの数を調整するオペレーターだという。

        再分割はシャッフルを経ますが、これは実際には coalesce(shuffle=true) 呼び出しです。

        合体、デフォルト shuffle=false、シャッフルは行われません。

        現在、合体演算子のみが考慮されていますが、公式の定義を見てみましょう。

        一般的な意味は、シャッフルせずに 1000 パーティションから 100 パーティションに変更する場合、10 個の親パーティションを 1 つの子パーティションにほぼ均等に分散することです。

        まず、私の簡単な理解を述べさせていただきます。シャッフルなしとは、合体オペレーターが前後で同じステージにあることを意味します。ステージの開始から合体オペレーターまでのタスクの反復実行の並列度は 1000、合体オペレーターの開始からステージの終了までのタスクの反復実行の並列度は 100 です。


val rdd1 = sc.parallelize(1 to 10, 10)

// 重新分区,分为两个2 ,不产生shuffle

val rdd2 = rdd1.coalesce(2, false)



// 获取新的RDD分区数

rdd2.partitions.length

def func1(index:Int,iter:Iterator[Int]):Iterator[String] = {

iter.toList.map(x=>"[PartID:"+index + ",value=" + x +"]").iterator

}

// 查看分区后的结果:

rdd2.mapPartitionsWithIndex(func1).collect



repartition:

val rdd1 = sc.parallelize(1 to 10, 4)

val rdd2 = rdd1.repartition(5)

集める、配列する

RDD を Scala 配列に変換します。

マップとして収集

collect や toArray に似ています。collectAsMap は、キーと値の RDD を Scala マップに変換します。

注: マップ内に同じキーがある場合は、最後の値のみが保存されます。


# 创建一个2分区的RDD

scala> var z = sc.parallelize(List( ("cat",2), ("cat", 5), ("mouse", 4),("cat", 12), ("dog", 12), ("mouse", 2)), 2)

z: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[129] at parallelize at <console>:21

# 输出所有分区的数据

scala> z.collect

res44: Array[(String, Int)] = Array((cat,2), (cat,5), (mouse,4), (cat,12), (dog,12), (mouse,2))



# 转化为字典

scala> z.collectAsMap

res45: scala.collection.Map[String,Int] = Map(dog -> 12, cat -> 12, mouse -> 2)

scala>


collectAsMap

val rdd = sc.parallelize(List(("a", 1), ("b", 2)))

rdd.collectAsMap

//res2: scala.collection.Map[String,Int] = Map(b -> 2, a -> 1)

combineByKey と aggregateByKey の比較:

  1. 1. 類似点:

  • どちらも、それぞれパーティション内計算とパーティション間計算のキー値をマップできます。

    2. 相違点:

  • combineByKey には 3 つのパラメータ リストがあり、初期値は必要ありませんが、aggregateByKey には 2 つのパラメータ リストしかなく、初期値が必要です。

aggregateByKeyパーティションでの計算の概略図

//aggregateByKey存在函数颗粒化,有两个参数列表

//第一个参数列表,需要传递一个参数,表示为初始值

// 主要当碰见第一个key时候,和value进行分区内计算

//第二个参数列表,需要传递2个参数

// 第一个参数表示分区内计算

// 第二个参数表示分区间计算



rdd.aggregateByKey(zeroValue = 0)(

(x, y) => math.max(x, y),

(x, y) => x + y

).collect().foreach(println)

パーティション内の CombineByKey 計算図

//combineByKey方法需要三个参数:

//第一个参数表示:将相同key的第一个数据进行结构转换,实现操作

//第二个参数:分区内的计算规则

//第三个参数:分区间的计算规则

val newRDD: RDD[(String, (Int, Int))] = rdd.combineByKey(

v => (v, 1),

(t: (Int, Int), v) => {

(t._1 + v, t._2 + 1)

},

(t1 Int: , t2: Int) => {

(t1._1 + t2._1, t1._2 + t2._2)

}

)

​

combineByKey と aggregateByKey の主な違いは、グループ内の最初の計算にわずかな違いがあることです。

combineByKey // はこのPairRDDFunctionsクラスのメソッドです

val rdd1 = sc.textFile("hdfs://Master:9000/input/word.txt").flatMap(_.split(" ")).map((_, 1))

val rdd2 = rdd1.combineByKey(x => x, (a: Int, b: Int) => a + b, (m: Int, n: Int) => m + n) // 等价与reduceByKey(_ + _),结果:Array[(String, Int)] =

Array((is,1), (Giuyang,1), (love,2), (capital,1), (Guiyang,1), (I,2), (of,1), (Guizhou,2), (the,1))

rdd2.collect

val rdd3 = rdd1.combineByKey(x => x + 10, (a: Int, b: Int) => a + b, (m: Int, n: Int) => m + n) // 将每个key的value各自加10,结果:Array[(String, Int)]

rdd3.collect

val rdd4 = sc.parallelize(List("dog","cat","gnu","salmon","rabbit","turkey","wolf","bear","bee"), 3)

val rdd5 = sc.parallelize(List(1,1,2,2,2,1,2,2,2), 3)

val rdd6 = rdd5.zip(rdd4)

​

1.Rddアクション演算子

1. [countByKey]は、RDD内のタプルに格納されているキーの数をカウントし、キーが同じ場合は+1します。このキーを使用してマップが生成されます。マップ内のキーは元のキーで、値は元のキーの数です。

2. [countByValue]は、Rddに格納されている要素の数をカウントします。RDD 内の各タプルは値とみなされ、このタプル内の要素が同じであれば、Map の value+1 が生成されます。

3. [filterByRange] は RDD 内の要素をフィルターし、指定された内容のデータを返します。この関数は、キーと値のペアの RDD に作用し、RDD 内の要素をフィルター処理して、キーが指定された範囲内にある要素を返します。

4. [ flatMapValues ] は主にタプル内に存在する値を平坦化します。

countByKey // 各キーの出現数をカウントします

val rdd1 = sc.parallelize(List(("a", 1), ("b", 2), ("b", 2), ("c", 2), ("c", 1)))

rdd1.countByKey

rdd1.countByValue  // countByValue返回每个值的出现次数

filterByRange // [filterByRange] rdd 内の要素をフィルターし、指定された範囲のコンテンツ データを返します。

val rdd1 = sc.parallelize(List(("e", 5), ("c", 3), ("d", 4), ("c", 2), ("a", 1)))

val rdd2 = rdd1.filterByRange("b", "d")

rdd2.collect

flatMapValues

val rdd3 = sc.parallelize(List(("a", "1 2"), ("b", "3 4")))

rdd3.flatMapValues(_.split(" "))

フォールドバイキー

関数プロトタイプ:

def foldByKey(zeroValue: V)(func: (V, V) => V): RDD[(K, V)]

def foldByKey(zeroValue: V, numPartitions: Int)(func: (V, V) => V): RDD[(K, V)]

def foldByKey(zeroValue: V, partitioner: Partitioner)(func: (V, V) => V): RDD[(K, V)]

 関数: K に従って RDD[K,V] を折りたたんでマージし、zeroValue を初期パラメーターとして使用し、func を呼び出して V を取得します。

次に、Key に応じた func に従って V が呼び出されます。

例:

scala> var rdd1 = sc.makeRDD(Array(("A",0),("A",2),("B",1),("B",2)))

rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[7] at makeRDD at <console>:27

scala> rdd1.foldByKey(0)(_+_).collect

res3: Array[(String, Int)] = Array((A,2), (B,3))

説明: __+_、Array(("A",0+0),("A",2+0)) に 0 を適用し、さらに処理して最終的に Array(("A",0+2)) を取得しますgetArray(("A",2))

フォールドバイキー

関数プロトタイプ:

def foldByKey(zeroValue: V)(func: (V, V) => V): RDD[(K, V)]

def foldByKey(zeroValue: V, numPartitions: Int)(func: (V, V) => V): RDD[(K, V)]

def foldByKey(zeroValue: V, partitioner: Partitioner)(func: (V, V) => V): RDD[(K, V)]

 関数: K に従って RDD[K,V] を折りたたんでマージし、zeroValue を初期パラメーターとして使用し、func を呼び出して V を取得します。

次に、Key に応じた func に従って V が呼び出されます。

例:

scala> var rdd1 = sc.makeRDD(Array(("A",0),("A",2),("B",1),("B",2)))

rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[7] at makeRDD at <console>:27

scala> rdd1.foldByKey(0)(_+_).collect

res3: Array[(String, Int)] = Array((A,2), (B,3))

説明: __+_、Array(("A",0+0),("A",2+0)) に 0 を適用し、さらに処理して最終的に Array(("A",0+2)) を取得しますgetArray(("A",2))

フォールドバイキー

val rdd1 = sc.parallelize(List("dog", "wolf", "cat", "bear"), 2)

val rdd2 = rdd1.map(x => (x.length, x))

val rdd3 = rdd2.foldByKey("")(_+_)

val rdd = sc.textFile("hdfs://Master:9000/input/word.txt").flatMap(_.split(" ")).map((_, 1))

rdd.foldByKey(0)(_+_)

foreachPartition // foreachPartition は、spark-core のアクション演算子です。この演算子のソース コードのコメントは次のとおりです: この RDD の各パーティションに関数 func を適用します (この RDD の各パーティションに関数 func を適用します)

val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)

rdd1.foreachPartition(x => println(x.reduce(_ + _)))

keyBy

val rdd1 = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)

val rdd2 = rdd1.keyBy(_.length)

rdd2.collect

キーの値

val rdd1 = sc.parallelize(List("dog", "tiger", "lion", "cat", "panther", "eagle"), 2)

val rdd2 = rdd1.map(x => (x.length, x))

rdd2.keys.collect

rdd2.values.collect

おすすめ

転載: blog.csdn.net/pblh123/article/details/133081483