算子:
轉換算子(transformation):懶加載,針對RDD操作
操作算子(Actions):即時執行,RDD轉化爲本地集合
即時執行的本地集合結果在Driver中
轉換算子可同時運行(😛能理解嗎?)
轉換操作:
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
2、collect() 將數據返回到 Driver,是以數組的形式返回數據集的所有元素(簡單測試用,生產環境中不用)
3、count() 返回 RDD 中的元素個數
4、first() 返回第一個元素
5、take(n) 返回前 n 個元素
6、takeSample(withReplacement, num, [seed]) 採樣,返回 Array 數組
7、takeOrdered (n) 返回排序後的前幾個元素,如果需要倒序,那麼可以利用重寫 Ordering 來做
8、aggregate (zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U)
9、fold(zeroValue)(func) aggregate 的簡化操作
10、saveAsTextFile(path) 以文本的方式保存到HDFS兼容的文件系統
11、saveAsSequenceFile(path) 以 SequenceFile 形式來存文件
12、saveAsObjectFile(path) 以 ObjectFile 來存文件
13、countByKey() 返回 Map 結構,獲取每一個 key 的數量
14、foreach(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;
}
}
);