Spark2 operator

算子:
轉換算子(transformation):懶加載,針對RDD操作
操作算子(Actions):即時執行,RDD轉化爲本地集合
即時執行的本地集合結果在Driver中

轉換算子可同時運行(😛能理解嗎?)
groupByKey和reduceByKey區別

轉換操作:
1、def map[U: ClassTag](f: T => U): RDD[U]      映射,將一種類型的數據轉換成爲另外一種類型的數據。
2、def filter(f: T => Boolean): RDD[T]          返回滿足條件的數據。
3、def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U]     將一個數據結構轉換成爲一個可迭代的數據結構,然後將數據壓平。
4、def mapPartitions[U: ClassTag](f: Iterator[T] => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]                    對於每一個分區執行一次函數,它的執行效率要比 map 高。
5、def mapPartitionsWithIndex[U: ClassTag](f: (Int, Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]    類似於 mapPartitions,但 func 帶有一個整數參數表示分片的索引值。
6、def sample(withReplacement: Boolean,fraction: Double,seed: Long = Utils.random.nextLong): RDD[T]     對 RDD 進行採樣,主要用於觀察大數據集的分佈情況。
7、def union(other: RDD[T]): RDD[T]             和另外一個 RDD 取並集。
8、def intersection(other: RDD[T]): RDD[T]      和另外一個 RDD 取交集。
9、def distinct(numPartitions: Int)             對原 RDD 進行去重後返回一個新的 RDD。
10、def partitionBy(partitioner: Partitioner): RDD[(K, V)]      對 KV 結構 RDD 進行重新分區。
11、def reduceByKey(func: (V, V) => V): RDD[(K, V)]             返回值 V 的數據類型必須和輸入一樣。先預聚合再聚集。
12、def groupByKey(partitioner: Partitioner): RDD[(K, Iterable[V])]     將相同 Key 的 value 進行聚集。
13、def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C): RDD[(K, C)]
    (1) 後面三個函數的邏輯是針對某一個 Key 的聚集來起作用。
    (2) createCombiner 每個分區都有,當遇到新 Key 的時候調用,產生一個新的數據結構。
    (3) mergeValue 每個分區都有,當遇到舊 Key 的時候調用,將當前數據合併到數據結構中。
    (4) mergeCombiners 這個是全局所有,合併所有分區中過來的數據。
14、def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner)(seqOp: (U, V) => U, combOp: (U, U) => U): RDD[(K, U)]
是 combineBykey 的簡化操作,zeroValue 類似於 createCombiner, seqOp 類似於 mergeValue, combOp 類似於 mergeCombiner。
15、def foldByKey(zeroValue: V, partitioner: Partitioner) (func: (V, V) => V): RDD[(K, V)]      注意:V 的類型不能改變。
16、def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.length): RDD[(K, V)]  對 KV 結構 RDD 進行排序(默認升序),K 必須實現 trait Ordering[T],複寫 compare 方法,返回一個按照 key 進行排序的 (K,V) 的 RDD。
17、def sortBy[K](f: (T) => K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]  sortBy 使用 func 產生的 Key 來做比較。
18、def join[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, W))]     和另外的 RDD 進行 JOIN。
19、def cogroup[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (Iterable[V], Iterable[W]))]      類似於兩個 RDD 分別做 groupByKey 然後再 全JOIN。
20、def cartesian[U: ClassTag](other: RDD[U]): RDD[(T, U)]      笛卡爾積。
21、def pipe(command: String): RDD[String]      對於每個分區,支持使用外部腳本比如 shell、perl 等處理分區內的數據。
22、def coalesce(numPartitions: Int, shuffle: Boolean = false,partitionCoalescer: Option[PartitionCoalescer] = Option.empty)(implicit ord: Ordering[T] = null): RDD[T]      改變分區數。
23、def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]       重新分區,所有數據全部網絡混洗。
24、def repartitionAndSortWithinPartitions(partitioner)     在重新分區的過程中會進行排序,如果重新分區後還要進行 sortBy 或者 sorkByKey 操作,那麼直接使用該算子。性能比 repartition 要高。
25、def glom(): RDD[Array[T]]       將每一個分區中的所有數據轉換爲一個 Array 數組,形成新的 RDD。
26、def mapValues[U](f: V => U): RDD[(K, U)]        只對 KV 結構中 value 數據進行映射。value 可以改變類型。
27、def subtract(other: RDD[T]): RDD[T]  求差集

----------------------------------------------------------------------------------------------------------

行動操作:
1、def reduce(f: (T, T) => T): T        規約某個 RDD
2collect()    將數據返回到 Driver,是以數組的形式返回數據集的所有元素(簡單測試用,生產環境中不用)
3count()      返回 RDD 中的元素個數
4first()      返回第一個元素
5take(n)      返回前 n 個元素
6takeSample(withReplacement, num, [seed])      採樣,返回 Array 數組
7、takeOrdered (n)      返回排序後的前幾個元素,如果需要倒序,那麼可以利用重寫 Ordering 來做
8、aggregate (zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U)  
9fold(zeroValue)(func)    aggregate 的簡化操作
10saveAsTextFile(path)        以文本的方式保存到HDFS兼容的文件系統
11saveAsSequenceFile(path)    以 SequenceFile 形式來存文件
12saveAsObjectFile(path)      以 ObjectFile 來存文件
13countByKey()        返回 Map 結構,獲取每一個 key 的數量
14foreach(func)       在數據集上的每一個元素運行 func 函數

使用示例(example)
aggregateByKey(代碼如下,key只作爲標識,提供兩個變量供設計計算算法)

public class OptTest {
    public static void main(String[] args) {
        SparkConf sc = new SparkConf().setAppName("").setMaster("local[2]");
        JavaSparkContext jsc = new JavaSparkContext(sc);
        jsc.setLogLevel("WARN");

        JavaRDD<Tuple2<Integer,Integer>> tupleRdd = jsc.parallelize(Arrays.asList(
                /**
                 * 1;9;3
                 * 2;3;1
                 * 3;14;2
                 */
                new Tuple2<Integer,Integer>(1,3),
                new Tuple2<Integer,Integer>(1,2),
                new Tuple2<Integer,Integer>(1,4),
                new Tuple2<Integer,Integer>(2,3),
                new Tuple2<Integer,Integer>(3,6),
                new Tuple2<Integer,Integer>(3,8)
                ...
        ));

        JavaPairRDD<Integer,Integer> pairRdd = tupleRdd.mapToPair(tuple->tuple);

        JavaPairRDD<Integer,Tuple2<Integer,Integer>> result =
        pairRdd.aggregateByKey(new Tuple2<Integer, Integer>(0, 0),
                new Function2<Tuple2<Integer, Integer>, Integer, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> tuple, Integer val2) throws Exception {
                        return new Tuple2<>(tuple._1() + val2, tuple._2() + 1);
                    }
                }, new Function2<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> tuple1, Tuple2<Integer, Integer> tuple2) throws Exception {
                        return new Tuple2<>(tuple1._1()+tuple2._1(),tuple1._2()+tuple2._2());
                    }
                }
        );

        result.foreach(new VoidFunction<Tuple2<Integer, Tuple2<Integer, Integer>>>() {
            @Override
            public void call(Tuple2<Integer, Tuple2<Integer, Integer>> res) throws Exception {
                System.out.println("res1:"+res._1+";res21:"+res._2._1+";res22:"+res._2._2);
            }
        });

        //--------------------
        JavaRDD<Tuple2<String,Integer>> msgRDD = jsc.parallelize(Arrays.asList(

                new Tuple2<String,Integer>("msg1",3),
                new Tuple2<String,Integer>("msg1",2),
                new Tuple2<String,Integer>("msg1",4),
                new Tuple2<String,Integer>("msg2",3),
                new Tuple2<String,Integer>("msg3",6),
                new Tuple2<String,Integer>("msg3",9),
                new Tuple2<String,Integer>("msg3",8)
                ...
        ));

        JavaPairRDD<String,Integer> msgPair = msgRDD.mapToPair(tuple->tuple);

        /**msgPair.aggregateByKey()打印結果
         *
         * return new Tuple2<>(tuple1._1+tuple2._1,tuple1._2+tuple2._2)的結果
         * msg1;9;3
         * msg2;3;1
         * msg3;168;24
         *
         * 分兩個分區後 分別return tuple1 和 tuple2 的結果
         * msg1;9;3
         * msg2;3;1
         * msg3;98;14
         *
         * msg1;9;3
         * msg2;3;1
         * msg3;70;10
         *
         * 由結果可知,第一個Function2爲分區內計算  第二個爲分區間的計算(第一個Function2的結果作爲第二個Function2的參數宏觀調用)
         */
        //sum and count
        JavaPairRDD<String,Tuple2<Integer,Integer>>  msgRes =
        msgPair.aggregateByKey(new Tuple2<Integer, Integer>(0, 0),new Integer(4),
                new Function2<Tuple2<Integer, Integer>, Integer, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> val1, Integer val2) throws Exception {
                        //分區內 param1 sum(val) param2 設計count遞增
                        return new Tuple2<>(val1._1 + val2, val1._2+1);//val1._1 + val2爲sum, val2, val1._2+1 每條記錄出現+1
                    }
                },
                new Function2<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> tuple1, Tuple2<Integer, Integer> tuple2) throws Exception {
                        //return new Tuple2<>(tuple1._1+tuple2._1,tuple1._2+tuple2._2);
                        return tuple2;//
                    }
                }
        );
        msgRes.foreach(new VoidFunction<Tuple2<String, Tuple2<Integer, Integer>>>() {
            @Override
            public void call(Tuple2<String, Tuple2<Integer, Integer>> msgTuple2) throws Exception {
                System.out.println(msgTuple2._1+";"+msgTuple2._2._1+";"+msgTuple2._2._2);
            }
        });

        //sum and max
        JavaPairRDD<String,Tuple2<Integer,Integer>>  msgMaxRes =
        msgPair.aggregateByKey(new Tuple2<Integer, Integer>(0, 0),
                new Function2<Tuple2<Integer, Integer>, Integer, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> val1, Integer val2) throws Exception {
                        return new Tuple2<Integer, Integer>(val1._1>val2?val1._1:val2,val1._2+1);
                    }
                },
                new Function2<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> tuple1, Tuple2<Integer, Integer> tuple2) throws Exception {
                        return new Tuple2<Integer, Integer>(tuple1._1>tuple2._1?tuple1._1:tuple2._1,tuple1._2+tuple2._2);
                    }
                }
        );

        msgMaxRes.foreach(new VoidFunction<Tuple2<String, Tuple2<Integer, Integer>>>() {
            @Override
            public void call(Tuple2<String, Tuple2<Integer, Integer>> msgTuple2) throws Exception {
                System.out.println(msgTuple2._1+";"+msgTuple2._2._1+";"+msgTuple2._2._2);
            }
        });
    }
}

//lambda版
msgPair.aggregate(new Tuple2<Integer, Integer>(0.0, 0), 
	     (x,y)->new Tuple2<Integer, Integer>(x._1+y,x._2+1),
	     (x,y)->new Tuple2<Integer, Integer>(x._1+y._1,x._2+y._2));

combineByKey( aggregateByKey是combineByKey的簡版)

/*********      combineByKey  start     **************/
        //sum and count
        JavaPairRDD<String,Tuple2<Integer,Integer>> pairRDD =
        msgPair.combineByKey(
                new Function<Integer, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer,Integer> call(Integer x) throws Exception {
                        return new Tuple2<Integer, Integer>(x,1);
                    }
                },
                new Function2<Tuple2<Integer, Integer>, Integer, Tuple2<Integer,Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> v, Integer x) throws Exception {
                        return new Tuple2<Integer, Integer>(v._1+x,v._2+1);
                    }
                },
                new Function2<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>, Tuple2<Integer, Integer>>() {
                    @Override
                    public Tuple2<Integer, Integer> call(Tuple2<Integer, Integer> v, Tuple2<Integer, Integer> v1) throws Exception {
                        return new Tuple2<Integer, Integer>(v._1+v1._1,v._2+v1._2);
                    }
                }
        );

        pairRDD.foreach(new VoidFunction<Tuple2<String, Tuple2<Integer, Integer>>>() {
            @Override
            public void call(Tuple2<String, Tuple2<Integer, Integer>> tuple2) throws Exception {
                System.out.println("combineByKey==="+tuple2._1+";"+tuple2._2._1+";"+tuple2._2._2);
            }
        });

foldByKey (上面兩種的精簡版)

//sum
JavaPairRDD<String,Integer> foldRDD =
msgPair.foldByKey(new Integer(0),
       new Function2<Integer, Integer, Integer>() {
           @Override
           public Integer call(Integer v1, Integer v2) throws Exception {
               return v1+v2;
           }
       }
);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章