2014年6月25日 星期三

Apache Spark學習筆記(4) Programming Guide Part 3

RDD Operations

RDDs support two types of operations: transformations, which create a new dataset from an existing one, and actions, which return a value to the driver program after running a computation on the dataset. For example, map is a transformation that passes each dataset element through a function and returns a new RDD representing the results. On the other hand, reduce is an action that aggregates all the elements of the RDD using some function and returns the final result to the driver program (although there is also a parallel reduceByKey that returns a distributed dataset).
All transformations in Spark are lazy, in that they do not compute their results right away. Instead, they just remember the transformations applied to some base dataset (e.g. a file). The transformations are only computed when an action requires a result to be returned to the driver program. This design enables Spark to run more efficiently – for example, we can realize that a dataset created through map will be used in a reduce and return only the result of the reduce to the driver, rather than the larger mapped dataset.
@@僅有action需要結果時才會真正執行運算, 好處是可以提升執行的效率, 例如wordcount範例, faltMap與map產生的中間暫存結果就不需要傳回到user app
By default, each transformed RDD may be recomputed each time you run an action on it. However, you may also persist an RDD in memory using the persist (or cache) method, in which case Spark will keep the elements around on the cluster for much faster access the next time you query it. There is also support for persisting RDDs on disk, or replicated across multiple nodes.
@@可以用 persist 或 cache 函式保存tranformation過程的RDD內容

Basics

To illustrate RDD basics, consider the simple program below:

val lines = sc.textFile("data.txt")
val lineLengths = lines.map(s => s.length)
val totalLength = lineLengths.reduce((a, b) => a + b)
The first line defines a base RDD from an external file. This dataset is not loaded in memory or otherwise acted on: lines is merely a pointer to the file. The second line defines lineLengths as the result of a map transformation. Again, lineLengths is not immediately computed, due to laziness. Finally, we run reduce, which is an action. At this point Spark breaks the computation into tasks to run on separate machines, and each machine runs both its part of the map and a local reduction, returning only its answer to the driver program.
@@textFile 僅建立指標指向外部檔案, map 僅記錄tramsformation過程, 執行 reduce 時才在各node執行map & reduce 運算task, 最後再將結果傳回user app
If we also wanted to use lineLengths again later, we could add:

lineLengths.persist()
before the reduce, which would cause lineLengths to be saved in memory after the first time it is computed.

Passing Functions to Spark

Spark’s API relies heavily on passing functions in the driver program to run on the cluster. There are two recommended ways to do this:
  • Anonymous function syntax, which can be used for short pieces of code.
  • Static methods in a global singleton object. For example, you can define object MyFunctions and then pass MyFunctions.func1, as follows:

object MyFunctions {
 def func1(s: String): String = { ... }
}

myRdd.map(MyFunctions.func1)
Note that while it is also possible to pass a reference to a method in a class instance (as opposed to a singleton object), this requires sending the object that contains that class along with the method. For example, consider:

class MyClass {
 def func1(s: String): String = { ... }
 def doStuff(rdd: RDD[String]): RDD[String] = { rdd.map(func1) }
}
Here, if we create a new MyClass and call doStuff on it, the map inside there references the func1 method of that MyClass instance, so the whole object needs to be sent to the cluster. It is similar to writing rdd.map(x => this.func1(x)).
@@可以設計class的method處理RDD, 注意這裡用 RDD[String] 宣告傳入參數與傳回結果的型態, 也可以呼叫rdd.map傳入function literal呼叫class instance obj的method,  

scala> val rdd1 = sc.textFile("hdfs://0a90e21c.cht.local:8020/tmp/s3log/S3log_2013012901_api1-8_cat")
scala> import org.apache.spark.rdd.RDD
scala> class MyClass {
 def f1(s: String) = { s.split(" ").size.toString }
 def work1(rdd: RDD[String]): RDD[String] = { rdd.map(f1) }
}
scala> val obj1 = new MyClass
scala> println(rdd1.first)
20130129000106, user1, user1, 10.144.30.153, 10.144.129.1, user1Bkt1, PutObject, 200, -, 10485760, -, 10485760
scala> println(obj1.work1(rdd1).first)
12
scala> println(rdd1.map(obj1.f1 _ ).first)
12

In a similar way, accessing fields of the outer object will reference the whole object:

class MyClass {
 val field = "Hello"
 def doStuff(rdd: RDD[String]): RDD[String] = { rdd.map(x => field + x) }
}
is equilvalent to writing rdd.map(x => this.field + x), which references all of this. To avoid this issue, the simplest way is to copy field into a local variable instead of accessing it externally:

def doStuff(rdd: RDD[String]): RDD[String] = {
 val field_ = this.field
 rdd.map(x => field_ + x)
}
@@可以設計class的method處理RDD時存取field, 也可以呼叫rdd.map傳入function literal存取class instance obj的field, 不過這樣需傳送整個obj至所有節點而影響效能, 可以將filed複製為變數給function literal使用
scala> val rdd1 = sc.textFile("hdfs://0a90e21c.cht.local:8020/tmp/s3log/S3log_2013012901_api1-8_cat")
scala> import org.apache.spark.rdd.RDD
scala> class MyClass {
 def f1(s: String) = { s.split(" ").size.toString }
 def work1(rdd: RDD[String]): RDD[String] = { rdd.map(f1) }
 val v1 = "Hi, "
 def f2(s:String) = { v1 + s.split(" ")(0) }
 def work2(rdd: RDD[String]): RDD[String] = { rdd.map(f2) }
}
scala> val obj2 = new MyClass
scala> println(rdd1.first)
20130129000106, user1, user1, 10.144.30.153, 10.144.129.1, user1Bkt1, PutObject, 200, -, 10485760, -, 10485760
scala> println(obj2.work2(rdd1).first)
Hi, 20130129000106,
scala> println(rdd1.map(obj2.f2 _).first)
Hi, 20130129000106,
scala> println(rdd1.map(obj2.f2).first)
Hi, 20130129000106,
 

Working with Key-Value Pairs

While most Spark operations work on RDDs containing any type of objects, a few special operations are only available on RDDs of key-value pairs. The most common ones are distibuted “shuffle” operations, such as grouping or aggregating the elements by a key.
In Scala, these operations are automatically available on RDDs containing Tuple2 objects (the built-in tuples in the language, created by simply writing (a, b)), as long as you import org.apache.spark.SparkContext._ in your program to enable Spark’s implicit conversions. The key-value pair operations are available in the PairRDDFunctions class, which automatically wraps around an RDD of tuples if you import the conversions.
For example, the following code uses the reduceB yKey operation on key-value pairs to count how many times each line of text occurs in a file:

val lines = sc.textFile("data.txt")
val pairs = lines.map(s => (s, 1))
val counts = pairs.reduceByKey((a, b) => a + b)
scala> val rdd1 = sc.textFile("hdfs://0a90e21c.cht.local:8020/tmp/s3log/S3log_2013012901_api1-8_cat")
scala> val pairs = rdd1.flatMap(_.split(" ")).map((_ , 1))
pairs: org.apache.spark.rdd.RDD[(String, Int)] = MappedRDD[33] at map at <console>:17
scala> val counts = pairs.reduceByKey( _ + _ )
counts: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[36] at reduceByKey at <console>:19
scala> val filters = counts.filter(_._1.contains("GetObject"))
filters: org.apache.spark.rdd.RDD[(String, Int)] = FilteredRDD[37] at filter at <console>:21
scala> filters.count
res40: Long = 1
@@由於RDD是分散儲存, 因此無法列印結果
scala> filters.foreach(kv => println("word["+ kv._1 +"] count["+ kv._2 +"]"))
...
14/06/11 17:42:23 INFO SparkContext: Job finished: foreach at <console>:24, took 0.117763755 s
scala> val res = filters.collect
res: Array[(String, Int)] = Array((GetObject,,6400000))
scala> filters.collect.foreach(kv => println("["+kv._1+"]["+kv._2+"]"))
[GetObject,][6400000]
scala>

We could also use counts.sortByKey(), for example, to sort the pairs alphabetically, and finally counts.collect() to bring them back to the driver program as an array of objects.

Transformations

The following table lists some of the common transformations supported by Spark. Refer to the RDD API doc (Scala, Java, Python) and pair RDD functions doc (Scala, Java) for details.
Meaning
def cartesian[U](other: RDD[U])(implicit arg0: ClassTag[U]): RDD[(T, U)]
Return the Cartesian product of this RDD and another one, that is, the RDD of all pairs of elements (a, b) where a is in this and b is in other.

When called on datasets of types T and U, returns a dataset of (T, U) pairs (all pairs of elements).

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14)) )
rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[0] at parallelize at <console>:12
scala> val rdd2 = sc.parallelize( List(("k3",23),("k3",25),("k3",28)) )
rdd2: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[1] at parallelize at <console>:12
scala> val rdd3 = rdd1.cartesian(rdd2)
rdd3: org.apache.spark.rdd.RDD[((String, Int), (String, Int))] = CartesianRDD[2] at cartesian at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:09:25 INFO SparkContext: Job finished: collect at <console>:18, took 3.352088019 s
col3: Array[((String, Int), (String, Int))] = Array(((k1,15),(k3,23)), ((k1,15),(k3,25)), ((k1,15),(k3,28)), ((k2,12),(k3,23)), ((k2,12),(k3,25)), ((k2,12),(k3,28)), ((k2,14),(k3,23)), ((k2,14),(k3,25)), ((k2,14),(k3,28)))

org.apache.spark.rdd.PairRDDFunctions

def cogroup[W1, W2](other1: RDD[(K, W1)], other2: RDD[(K, W2)], numPartitions: Int): RDD[(K, (Iterable[V], Iterable[W1],Iterable[W2]))]
For each key k in this or other1 or other2, return a resulting RDD that contains a tuple with the list of values for that key in this, other1 and other2.

def cogroup[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (Iterable[V], Iterable[W]))]
For each key k in this or other, return a resulting RDD that contains a tuple with the list of values for that key in this as well as other.

def cogroup[W1, W2](other1: RDD[(K, W1)], other2: RDD[(K, W2)]): RDD[(K, (Iterable[V], Iterable[W1], Iterable[W2]))]
For each key k in this or other1 or other2, return a resulting RDD that contains a tuple with the list of values for that key in this, other1 and other2.

def cogroup[W](other: RDD[(K, W)]): RDD[(K, (Iterable[V], Iterable[W]))]
For each key k in this or other, return a resulting RDD that contains a tuple with the list of values for that key in this as well as other.

def cogroup[W1, W2](other1: RDD[(K, W1)], other2: RDD[(K, W2)], partitioner: Partitioner): RDD[(K, (Iterable[V], Iterable[W1],Iterable[W2]))]
For each key k in this or other1 or other2, return a resulting RDD that contains a tuple with the list of values for that key in this, other1 and other2.

def cogroup[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (Iterable[V], Iterable[W]))]
For each key k in this or other, return a resulting RDD that contains a tuple with the list of values for that key in this as well as other.

When called on datasets of type (K, V) and (K, W), returns a dataset of (K, Iterable<V>, Iterable<W>) tuples. This operation is also called groupWith.
                                                                                                                  K, 1st RDD    , 2nd RDD
scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18)) )
scala> val rdd2 = sc.parallelize( List(("k1",25),("k2",22),("k2",24),("k3",23),("k3",25),("k3",28)) )
scala> val rdd3 = rdd1.cogroup(rdd2)
rdd3: org.apache.spark.rdd.RDD[(String, (Iterable[Int], Iterable[Int]))] = MappedValuesRDD[21] at cogroup at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:10:15 INFO SparkContext: Job finished: collect at <console>:18, took 0.362600052 s
col3: Array[(String, (Iterable[Int], Iterable[Int]))] = Array((k1,(ArrayBuffer(15),ArrayBuffer(25))), (k2,(ArrayBuffer(12, 14),ArrayBuffer(22, 24))), (k3,(ArrayBuffer(13, 15, 18),ArrayBuffer(23, 25, 28))))
def coalesce(numPartitions: Int, shuffle: Boolean = false)(implicit ord: Ordering[T] = null): RDD[T]
Return a new RDD that is reduced into numPartitions partitions.
This results in a narrow dependency, e.g. if you go from 1000 partitions to 100 partitions, there will not be a shuffle, instead each of the 100 new partitions will claim 10 of the current partitions.
However, if you're doing a drastic coalesce, e.g. to numPartitions = 1, this may result in your computation taking place on fewer nodes than you like (e.g. one node in the case of numPartitions = 1). To avoid this, you can pass shuffle = true. This will add a shuffle step, but means the current upstream partitions will be executed in parallel (per whatever the current partitioning is).
Note: With shuffle = true, you can actually coalesce to a larger number of partitions. This is useful if you have a small number of partitions, say 100, potentially with a few partitions being abnormally large. Calling coalesce(1000, shuffle = true) will result in 1000 partitions with the data distributed using a hash partitioner.

Decrease the number of partitions in the RDD to numPartitions. Useful for running operations more efficiently after filtering down a large dataset.

scala> val rdd1 = sc.parallelize( 1 to 1000000000, 72)
scala> val rdd3 = rdd1.coalesce(3, false)
rdd3: org.apache.spark.rdd.RDD[Int] = CoalescedRDD[89] at coalesce at <console>:14
scala> rdd3.partitions
res4: Array[org.apache.spark.Partition] = Array(CoalescedRDDPartition(0,ParallelCollectionRDD[88] at parallelize at <console>:12,[I@1c414bd8,), CoalescedRDDPartition(1,ParallelCollectionRDD[88] at parallelize at <console>:12,[I@2da6066,), CoalescedRDDPartition(2,ParallelCollectionRDD[88] at parallelize at <console>:12,[I@4eeeca00,))
scala> rdd3.partitions.length
res7: Int = 3
scala> rdd3.partitions(1)
res5: org.apache.spark.Partition = CoalescedRDDPartition(1,ParallelCollectionRDD[88] at parallelize at <console>:12,[I@2da6066,)
scala> rdd3.first
14/06/17 16:57:34 INFO SparkContext: Starting job: first at <console>:17
14/06/17 16:57:34 INFO DAGScheduler: Got job 32 (first at <console>:17) with 1 output partitions (allowLocal=true)
14/06/17 16:57:34 INFO DAGScheduler: Final stage: Stage 46(first at <console>:17)
14/06/17 16:57:34 INFO DAGScheduler: Parents of final stage: List()
14/06/17 16:57:34 INFO DAGScheduler: Missing parents: List()
14/06/17 16:57:34 INFO DAGScheduler: Computing the requested partition locally
14/06/17 16:57:34 INFO SparkContext: Job finished: first at <console>:17, took 0.006004786 s
res9: Int = 1

scala> val rdd4 = rdd1.coalesce(3, true)
rdd3: org.apache.spark.rdd.RDD[Int] = MappedRDD[93] at coalesce at <console>:14
scala> rdd4.first
14/06/17 16:58:34 INFO SparkContext: Starting job: first at <console>:17
14/06/17 16:58:34 INFO DAGScheduler: Registering RDD 95 (coalesce at <console>:14)
14/06/17 16:58:34 INFO DAGScheduler: Got job 33 (first at <console>:17) with 1 output partitions (allowLocal=true)
14/06/17 16:58:34 INFO DAGScheduler: Final stage: Stage 47(first at <console>:17)
14/06/17 16:58:34 INFO DAGScheduler: Parents of final stage: List(Stage 48)
14/06/17 16:58:34 INFO DAGScheduler: Missing parents: List(Stage 48)
14/06/17 16:58:34 INFO DAGScheduler: Submitting Stage 48 (MapPartitionsRDD[95] at coalesce at <console>:14), which has no missing parents
14/06/17 16:58:34 INFO DAGScheduler: Submitting 72 missing tasks from Stage 48 (MapPartitionsRDD[95] at coalesce at <console>:14)
14/06/17 16:58:34 INFO TaskSchedulerImpl: Adding task set 48.0 with 72 tasks
...
14/06/17 17:00:47 INFO DAGScheduler: Stage 48 (coalesce at <console>:14) finished in 133.428 s
...
14/06/17 17:00:47 INFO DAGScheduler: Submitting 1 missing tasks from Stage 47 (MappedRDD[98] at coalesce at <console>:14)
14/06/17 17:00:47 INFO TaskSchedulerImpl: Adding task set 47.0 with 1 tasks
...
14/06/17 17:00:47 INFO DAGScheduler: Stage 47 (first at <console>:17) finished in 0.051 s
14/06/17 17:00:47 INFO SparkContext: Job finished: first at <console>:17, took 133.494887493 s
res10: Int = 3
def distinct(): RDD[T]
Return a new RDD containing the distinct elements in this RDD.

def distinct(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]
Return a new RDD containing the distinct elements in this RDD.

Return a new dataset that contains the distinct elements of the source dataset.
scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18)) )
scala> val rdd3 = rdd1.distinct()
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MappedRDD[14] at distinct at <console>:14
scala> val col3 = rdd3.collect
...
14/06/17 16:10:45 INFO SparkContext: Job finished: collect at <console>:16, took 0.170900447 s
col3: Array[(String, Int)] = Array((k3,15), (k2,12), (k2,14), (k3,18), (k1,15), (k3,13))

scala> val rdd2 = sc.parallelize( List("k1","k2","k2","k3","k3","k3") )
scala> val rdd3 = rdd2.distinct()
scala> val col3 = rdd3.collect
col3: Array[String] = Array(k1, k2, k3)
def filter(f: (T) ⇒ Boolean): RDD[T]
Return a new RDD containing only the elements that satisfy a predicate.
@@func傳入單一參數型態T, 傳回單一結果型態boolean
Return a new dataset formed by selecting those elements of the source on which func returns true.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18)) )
scala> val rdd3 = rdd1.filter( _._1.contains("k2") )
scala> val col3 = rdd3.collect
...
14/06/17 16:11:10 INFO SparkContext: Job finished: collect at <console>:16, took 0.091217961 s
col3: Array[(String, Int)] = Array((k2,12), (k2,14))
def flatMap[U](f: (T) ⇒ TraversableOnce[U])(implicit arg0: ClassTag[U]): RDD[U]
Return a new RDD by first applying a function to all elements of this RDD, and then flattening the results.
@@func傳入單一參數型態T, 傳回多個結果Seq型態U
Similar to map, but each input item can be mapped to 0 or more output items (so func should return a Seq rather than a single item).

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18)) )
scala> val rdd3 = rdd1.flatMap( tup => List(tup._1 , tup._2) )
scala> val col3 = rdd3.collect
...
14/06/17 16:11:43 INFO SparkContext: Job finished: collect at <console>:16, took 0.071136612 s
col3: Array[Any] = Array(k1, 15, k2, 12, k2, 14, k3, 13, k3, 15, k3, 18)
def groupBy[K](f: (T) ⇒ K, p: Partitioner)(implicit kt: ClassTag[K], ord: Ordering[K] = null): RDD[(K, Iterable[T])]
Return an RDD of grouped items. Each group consists of a key and a sequence of elements mapping to that key.

def groupBy[K](f: (T) ⇒ K, numPartitions: Int)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
Return an RDD of grouped elements. Each group consists of a key and a sequence of elements mapping to that key.

def groupBy[K](f: (T) ⇒ K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
Return an RDD of grouped items. Each group consists of a key and a sequence of elements mapping to that key.

scala> val rdd1 = sc.parallelize( 1 to 999)
scala> val rdd3 = rdd1.groupBy
rdd3: org.apache.spark.rdd.RDD[(String, Iterable[Int])] = MappedValuesRDD[12] at groupByKey at <console>:14
scala> val col3 = rdd3.collect
...
14/06/17 16:12:09 INFO SparkContext: Job finished: collect at <console>:16, took 0.176309621 s
col3: Array[(String, Iterable[Int])] = Array((k1, ArrayBuffer(15)) , (k2, ArrayBuffer(12, 14)) , (k3, ArrayBuffer(13, 15, 18)))

org.apache.spark.rdd.PairRDDFunctions

def groupByKey(): RDD[(K, Iterable[V])]
Group the values for each key in the RDD into a single sequence. Hash-partitions the resulting RDD with the existing partitioner/parallelism level.
Note: If you are grouping in order to perform an aggregation (such as a sum or average) over each key, using PairRDDFunctions.reduceByKey or PairRDDFunctions.combineByKeywill provide much better performance,

def groupByKey(numPartitions: Int): RDD[(K, Iterable[V])]
Group the values for each key in the RDD into a single sequence. Hash-partitions the resulting RDD with into numPartitions partitions.
Note: If you are grouping in order to perform an aggregation (such as a sum or average) over each key, using PairRDDFunctions.reduceByKey or PairRDDFunctions.combineByKeywill provide much better performance.

def groupByKey(partitioner: Partitioner): RDD[(K, Iterable[V])]
Group the values for each key in the RDD into a single sequence. Allows controlling the partitioning of the resulting key-value pair RDD by passing a Partitioner.
Note: If you are grouping in order to perform an aggregation (such as a sum or average) over each key, using PairRDDFunctions.reduceByKey or PairRDDFunctions.combineByKeywill provide much better performance.

When called on a dataset of (K, V) pairs, returns a dataset of (K, Iterable<V>) pairs.
Note: If you are grouping in order to perform an aggregation (such as a sum or average) over each key, using reduceByKey or combineByKey will yield much better performance.
Note: By default, the level of parallelism in the output depends on the number of partitions of the parent RDD. You can pass an optional numTasks argument to set a different number of tasks.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18)) )
scala> val rdd3 = rdd1.groupByKey
rdd3: org.apache.spark.rdd.RDD[(String, Iterable[Int])] = MappedValuesRDD[12] at groupByKey at <console>:14
scala> val col3 = rdd3.collect
...
14/06/17 16:12:09 INFO SparkContext: Job finished: collect at <console>:16, took 0.176309621 s
col3: Array[(String, Iterable[Int])] = Array((k1, ArrayBuffer(15)) , (k2, ArrayBuffer(12, 14)) , (k3, ArrayBuffer(13, 15, 18)))

org.apache.spark.rdd.DoubleRDDFunctions

def histogram(buckets: Array[Double], evenBuckets: Boolean = false): Array[Long]
Compute a histogram using the provided buckets. The buckets are all open to the left except for the last which is closed e.g. for the array [1, 10, 20, 50] the buckets are [1, 10) [10, 20) [20, 50] e.g 1<=x<10 , 10<=x<20, 20<=x<50 And on the input of 1 and 50 we would have a histogram of 1, 0, 0
Note: if your histogram is evenly spaced (e.g. [0, 10, 20, 30]) this can be switched from an O(log n) inseration to O(1) per element. (where n = # buckets) if you set evenBuckets to true. buckets must be sorted and not contain any duplicates. buckets array must be at least two elements All NaN entries are treated the same. If you have a NaN bucket it must be the maximum value of the last position and all NaN entries will be counted in that bucket.

def histogram(bucketCount: Int): (Array[Double], Array[Long])
Compute a histogram of the data using bucketCount number of buckets evenly spaced between the minimum and maximum of the RDD. For example if the min value is 0 and the max is 100 and there are two buckets the resulting buckets will be [0, 50) [50, 100]. bucketCount must be at least 1 If the RDD contains infinity, NaN throws an exception If the elements in RDD do not vary (max == min) always returns a single bucket.
def intersection(other: RDD[T]): RDD[T]
Return the intersection of this RDD and another one. The output will not contain any duplicate elements, even if the input RDDs did. Note that this method performs a shuffle internally.

Return a new RDD that contains the intersection of elements in the source dataset and the argument.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18)) )
scala> val rdd2 = sc.parallelize( List(("k1",25),("k2",12),("k2",24),("k3",23),("k3",15),("k3",28)) )
scala> val rdd3 = rdd1.intersection(rdd2)
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MappedRDD[31] at intersection at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:12:40 INFO SparkContext: Job finished: collect at <console>:18, took 0.121664781 s
col3: Array[(String, Int)] = Array((k3,15), (k2,12))

org.apache.spark.rdd.PairRDDFunctions

def join[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, W))]
Return an RDD containing all pairs of elements with matching keys in this and other. Each pair of elements will be returned as a (k, (v1, v2)) tuple, where (k, v1) is in this and (k, v2) is in other. Performs a hash join across the cluster.

def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
Return an RDD containing all pairs of elements with matching keys in this and other. Each pair of elements will be returned as a (k, (v1, v2)) tuple, where (k, v1) is in this and (k, v2) is in other. Performs a hash join across the cluster.

def join[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, W))]
Return an RDD containing all pairs of elements with matching keys in this and other. Each pair of elements will be returned as a (k, (v1, v2)) tuple, where (k, v1) is in this and (k, v2) is in other. Uses the given Partitioner to partition the output RDD.

When called on datasets of type (K, V) and (K, W), returns a dataset of (K, (V, W)) pairs with all pairs of elements for each key. Outer joins are also supported through leftOuterJoin and rightOuterJoin.
@@join產生tuple of (key, tuple of values)
scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)) )
scala> val rdd2 = sc.parallelize( List(("k1",25),("k2",22),("k2",14),("k3",23),("k3",15),("k3",28),("k5",29)) )
scala> val rdd3 = rdd1.join(rdd2)
rdd3: org.apache.spark.rdd.RDD[(String, (Int, Int))] = FlatMappedValuesRDD[23] at join at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:13:13 INFO SparkContext: Job finished: collect at <console>:18, took 0.159721377 s
col3: Array[(String, (Int, Int))] = Array((k1,(15,25)) ,
(k2,(14,14)), (k2,(14,22)), (k2,(12,14)), (k2,(12,22)),
(k3,(15,23)), (k3,(15,28)), (k3,(15,15)), (k3,(13,23)), (k3,(13,28)), (k3,(13,15)), (k3,(18,23)), (k3,(18,28)), (k3,(18,15)))


def leftOuterJoin[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, Option[W]))]
Perform a left outer join of this and other. For each element (k, v) in this, the resulting RDD will either contain all pairs (k, (v, Some(w))) for w in other, or the pair (k, (v, None)) if no elements in other have key k. Hash-partitions the output into numPartitions partitions.

def leftOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (V, Option[W]))]
Perform a left outer join of this and other. For each element (k, v) in this, the resulting RDD will either contain all pairs (k, (v, Some(w))) for w in other, or the pair (k, (v, None)) if no elements in other have key k. Hash-partitions the output using the existing partitioner/parallelism level.

def leftOuterJoin[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, Option[W]))]
Perform a left outer join of this and other. For each element (k, v) in this, the resulting RDD will either contain all pairs (k, (v, Some(w))) for w in other, or the pair (k, (v, None)) if no elements in other have key k. Uses the given Partitioner to partition the output RDD.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)) )
scala> val rdd2 = sc.parallelize( List(("k1",25),("k2",22),("k2",14),("k3",23),("k3",15),("k3",28),("k5",29)) )
scala> val rdd3 = rdd1.leftOuterJoin(rdd2)
rdd3: org.apache.spark.rdd.RDD[(String, (Int, Option[Int]))] = FlatMappedValuesRDD[44] at leftOuterJoin at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:15:36 INFO SparkContext: Job finished: collect at <console>:18, took 0.138889033 s
col3: Array[(String, (Int, Option[Int]))] = Array((k1,(15,Some(25))),
(k2,(14,Some(22))), (k2,(14,Some(14))), (k2,(12,Some(22))), (k2,(12,Some(14))),
(k3,(13,Some(23))), (k3,(13,Some(15))), (k3,(13,Some(28))), (k3,(15,Some(23))), (k3,(15,Some(15))), (k3,(15,Some(28))), (k3,(18,Some(23))),
(k3,(18,Some(15))), (k3,(18,Some(28))), (k4,(19,None)))

def rightOuterJoin[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (Option[V], W))]
Perform a right outer join of this and other. For each element (k, w) in other, the resulting RDD will either contain all pairs (k, (Some(v), w)) for v in this, or the pair (k, (None, w)) if no elements in this have key k. Hash-partitions the resulting RDD into the given number of partitions.

def rightOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (Option[V], W))]
Perform a right outer join of this and other. For each element (k, w) in other, the resulting RDD will either contain all pairs (k, (Some(v), w)) for v in this, or the pair (k, (None, w)) if no elements in this have key k. Hash-partitions the resulting RDD using the existing partitioner/parallelism level.

def rightOuterJoin[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (Option[V], W))]
Perform a right outer join of this and other. For each element (k, w) in other, the resulting RDD will either contain all pairs (k, (Some(v), w)) for v in this, or the pair (k, (None, w)) if no elements in this have key k. Uses the given Partitioner to partition the output RDD.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)) )
scala> val rdd2 = sc.parallelize( List(("k1",25),("k2",22),("k2",14),("k3",23),("k3",15),("k3",28),("k5",29)) )
scala> val rdd3 = rdd1.rightOuterJoin(rdd2)
rdd3: org.apache.spark.rdd.RDD[(String, (Option[Int], Int))] = FlatMappedValuesRDD[47] at rightOuterJoin at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:16:38 INFO SparkContext: Job finished: collect at <console>:18, took 0.191968032 s
col3: Array[(String, (Option[Int], Int))] = Array((k1,(Some(15),25)),
(k2,(Some(14),22)), (k2,(Some(14),14)), (k2,(Some(12),22)), (k2,(Some(12),14)),
(k3,(Some(13),23)), (k3,(Some(13),15)), (k3,(Some(13),28)), (k3,(Some(15),23)), (k3,(Some(15),15)), (k3,(Some(15),28)), (k3,(Some(18),23)),
(k3,(Some(18),15)), (k3,(Some(18),28)), (k5,(None,29)))
def map[U](f: (T) ⇒ U)(implicit arg0: ClassTag[U]): RDD[U]
Return a new RDD by applying a function to all elements of this RDD.
@@func傳入單一參數型態T, 傳回單一結果型態T
Return a new distributed dataset formed by passing each element of the source through a function func.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)) )
scala> val var1 = 10
scala> val rdd3 = rdd1.map( tup => (tup._1 , tup._2 + var1) )
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MappedRDD[14] at map at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:17:37 INFO SparkContext: Job finished: collect at <console>:18, took 0.13497762 s
col3: Array[(String, Int)] = Array((k1,25), (k2,22), (k2,24), (k3,23), (k3,25), (k3,28), (k4,29))
def mapPartitions[U](f: (Iterator[T]) ⇒ Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U]
Return a new RDD by applying a function to each partition of this RDD.
@@func傳入多個參數Iterator型態T, 傳回多個結果Iterator型態U
Similar to map, but runs separately on each partition (block) of the RDD, so func must be of type Iterator<T> => Iterator<U> when running on an RDD of type T.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)), 3)
scala> val var1 = 10
scala> val rdd3 = rdd1.mapPartitions( ite => { for (i <- ite if i._2 > 15) yield (i._1, i._2 + var1) } )
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[26] at mapPartitions at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:18:24 INFO SparkContext: Job finished: collect at <console>:18, took 0.081354954 s
col3: Array[(String, Int)] = = Array((k3,28), (k4,29))
def mapPartitionsWithContext[U](f: (TaskContext, Iterator[T]) ⇒ Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U]
Return a new RDD by applying a function to each partition of this RDD. This is a variant of mapPartitions that also passes the TaskContext into the closure.
@@func傳入多個參數Iterator型態T, 傳回多個結果Iterator型態U

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)), 3)
scala> val var1 = 10
scala> val rdd3 = rdd1.mapPartitionsWithContext( (tc, ite) => {
 tc.addOnCompleteCallback(() => println("Partition: " + tc.partitionId + ", AttemptID: " + tc.attemptId + ", Interrupted: " + tc.interrupted))  
 ite.toList.filter(_._2 % 2 == 0).iterator
 }
)
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[32] at mapPartitionsWithContext at <console>:14
scala> val col3 = rdd3.collect
...
14/06/17 16:19:18 INFO SparkContext: Job finished: collect at <console>:16, took 0.026602068 s
col3: Array[(String, Int)] = Array((k2,12), (k2,14), (k3,18))
@@ Spark Master UI -> Application Name: Spark Shell -> Worker: worker-20140609105100-0a90e21e.cht.local-37050 stdout ->
def mapPartitionsWithIndex[U](f: (Int, Iterator[T]) ⇒ Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]):RDD[U]
Return a new RDD by applying a function to each partition of this RDD, while tracking the index of the original partition.
@@func傳入多個參數Iterator型態T, 傳回多個結果Iterator型態U
Similar to mapPartitions, but also provides func with an integer value representing the index of the partition, so func must be of type (Int, Iterator<T>) => Iterator<U> when running on an RDD of type T.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)), 3)
scala> val var1 = 10
scala> val rdd3 = rdd1.mapPartitionsWithIndex( (idx, ite) => { for (i <- ite if (i._2 % 2 == 0) ) yield (idx, i._1, i._2 + var1) } )
rdd3: org.apache.spark.rdd.RDD[(Int, String, Int)] = MapPartitionsRDD[30] at mapPartitionsWithIndex at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:31:54 INFO SparkContext: Job finished: collect at <console>:18, took 0.077283621 s
col3: Array[(Int, String, Int)] = Array((0,k2,22), (1,k2,24), (2,k3,28))
def pipe(command: Seq[String], env: Map[String, String] = Map(), printPipeContext: ((String) ⇒ Unit) ⇒ Unit = null, printRDDElement: (T, (String) ⇒ Unit) ⇒ Unit = null, separateWorkingDir: Boolean = false): RDD[String]
Return an RDD created by piping elements to a forked external process. The print behavior can be customized by providing two functions.
command : command to run in forked process.
env : environment variables to set.
printPipeContext : Before piping elements, this function is called as an oppotunity to pipe context data. Print line function (like out.println) will be passed as printPipeContext's parameter.
printRDDElement : Use this function to customize how to pipe elements. This function will be called with each RDD element as the 1st parameter, and the print line function (like out.println()) as the 2nd parameter. An example of pipe the RDD data of groupBy() in a streaming way, instead of constructing a huge String to concat all the elements: def printRDDElement(record:(String, Seq[String]), f:String=>Unit) = for (e <- record._2){f(e)}
separateWorkingDir : Use separate working directories for each task.
returns : the result RDD

def pipe(command: String, env: Map[String, String]): RDD[String]
Return an RDD created by piping elements to a forked external process.

def pipe(command: String): RDD[String]
Return an RDD created by piping elements to a forked external process.
@@根據partition數目, 平行將RDD partition的成員導向command的stdin, 並將command的stdout收集為RDD[String]的partition
Pipe each partition of the RDD through a shell command, e.g. a Perl or bash script. RDD elements are written to the process's stdin and lines output to its stdout are returned as an RDD of strings.

@@1 to 9 分為3個partition, 各為(1,2,3) (4,5,6) (7,8,9), 平行導向”head -n 1”的輸出為 (“1”), (“4”), (“9”)
scala> val rdd1 = sc.parallelize( 1 to 9, 3)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:12
scala> val rdd3 = rdd1.pipe("head -n 1")
rdd3: org.apache.spark.rdd.RDD[String] = PipedRDD[1] at pipe at <console>:14
scala> val col3 = rdd3.collect
...
14/06/17 16:33:10 INFO SparkContext: Job finished: collect at <console>:16, took 0.054902567 s
col3: Array[String] = Array(1, 4, 7)

org.apache.spark.rdd.PairRDDFunctions

def reduceByKey(func: (V, V) ⇒ V): RDD[(K, V)]
Merge the values for each key using an associative reduce function. This will also perform the merging locally on each mapper before sending results to a reducer, similarly to a "combiner" in MapReduce. Output will be hash-partitioned with the existing partitioner/ parallelism level

def reduceByKey(func: (V, V) ⇒ V, numPartitions: Int): RDD[(K, V)]
Merge the values for each key using an associative reduce function. This will also perform the merging locally on each mapper before sending results to a reducer, similarly to a "combiner" in MapReduce. Output will be hash-partitioned with numPartitions partitions.

def reduceByKey(partitioner: Partitioner, func: (V, V) ⇒ V): RDD[(K, V)]
Merge the values for each key using an associative reduce function. This will also perform the merging locally on each mapper before sending results to a reducer, similarly to a "combiner" in MapReduce.

def reduceByKeyLocally(func: (V, V) ⇒ V): Map[K, V]
Merge the values for each key using an associative reduce function, but return the results immediately to the master as a Map. This will also perform the merging locally on each mapper before sending results to a reducer, similarly to a "combiner" in MapReduce.

When called on a dataset of (K, V) pairs, returns a dataset of (K, V) pairs where the values for each key are aggregated using the given reduce function. Like in groupByKey, the number of reduce tasks is configurable through an optional second argument.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)), 3)
scala> val var1 = 10
scala> val rdd3 = rdd1.reduceByKey( _ + _ + var1 )
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[13] at reduceByKey at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:35:32 INFO SparkContext: Job finished: collect at <console>:18, took 0.090013474 s
col3: Array[(String, Int)] = Array((k1,15), (k4,19), (k2,36), (k3,66))
def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]
Return a new RDD that has exactly numPartitions partitions.
Can increase or decrease the level of parallelism in this RDD. Internally, this uses a shuffle to redistribute data.
If you are decreasing the number of partitions in this RDD, consider using coalesce, which can avoid performing a shuffle.
@@可以增加或減少partition數目, 一定會產生shuffle步驟, 如果是減少partition的話可考慮使用colease不用shuffle
Reshuffle the data in the RDD randomly to create either more or fewer partitions and balance it across them. This always shuffles all data over the network.

scala> val rdd1 = sc.parallelize( 1 to 1000000000, 72)
scala> val rdd3 = rdd1.repartition(3)
rdd3: org.apache.spark.rdd.RDD[Int] = MappedRDD[103] at repartition at <console>:14
scala> rdd3.first

.
def sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T]
Return a sampled subset of this RDD.
core/src/main/scala/org/apache/spark/rdd/RDD.scala
@@withR=true => use PoissonSampler, withR=false => BernoulliSampler
Sample a fraction fraction of the data, with or without replacement, using a given random number generator seed.

scala> val rdd1 = sc.parallelize( 1 to 1000000000)
scala> val rdd3 = rdd1.sample(true, 0.5)
rdd3: org.apache.spark.rdd.RDD[Int] = PartitionwiseSampledRDD[16] at sample at <console>:14
scala> val col3 = rdd3.stats
...
14/06/17 16:36:17 INFO SparkContext: Job finished: stats at <console>:16, took 10.068651352 s
col3: org.apache.spark.util.StatCounter = (count: 499985095, mean: 499995919.773215, stdev: 288669213.425923, max: 999999999.000000, min: 1.000000)

scala> val rdd4 = rdd1.sample(true, 0.4)
scala> val col4 = rdd4.stats
...
14/06/17 16:36:50 INFO SparkContext: Job finished: stats at <console>:16, took 16.034619528 s
col4: org.apache.spark.util.StatCounter = (count: 399988195, mean: 500023354.299222, stdev: 288674538.290221, max: 999999998.000000, min: 3.000000)
...

org.apache.spark.rdd.OrderedRDDFunctions

def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.size): RDD[P]
Sort the RDD by key, so that each partition contains a sorted range of the elements. Calling collect or save on the resulting RDD will return or output an ordered list of records (in thesave case, they will be written to multiple part-X files in the filesystem, in order of the keys).

When called on a dataset of (K, V) pairs where K implements Ordered, returns a dataset of (K, V) pairs sorted by keys in ascending or descending order, as specified in the boolean ascending argument.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)))
scala> val rdd3 = rdd1.sortByKey(false)
...
14/06/17 16:02:59 INFO SparkContext: Job finished: sortByKey at <console>:14, took 0.122243002 s
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[12] at sortByKey at <console>:14
scala> val col3 = rdd3.collect
...
14/06/17 16:05:20 INFO DAGScheduler: Stage 5 (collect at <console>:16) finished in 0.237 s
col3: Array[(String, Int)] = Array((k4,19), (k3,18), (k3,15), (k3,13), (k2,14), (k2,12), (k1,15))
def union(other: RDD[T]): RDD[T]
Return the union of this RDD and another one.

Return a new dataset that contains the union of the elements in the source dataset and the argument.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)) )
scala> val rdd2 = sc.parallelize( List(("k1",25),("k2",22),("k2",14),("k3",23),("k3",15),("k3",28),("k5",29)) )
scala> val rdd3 = rdd1.union(rdd2)
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = UnionRDD[87] at union at <console>:16
scala> val col3 = rdd3.collect
...
14/06/17 16:39:34 INFO SparkContext: Job finished: collect at <console>:18, took 0.100942087 s
col3: Array[(String, Int)] = Array((k1,15), (k2,12), (k2,14), (k3,13), (k3,15), (k3,18), (k4,19), (k1,25), (k2,22), (k2,14), (k3,23), (k3,15), (k3,28), (k5,29))

@@對 RDD[key:String, value:Int] 計算每個Key的平均值
scala> val rdd1 = sc.parallelize( List(("k1",1),("k2",2),("k2",2),("k3",3),("k3",3),("k3",3)) )
rdd: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[8] at parallelize at <console>:12
scala> val rdd2 = rdd.groupByKey()
rdd2: org.apache.spark.rdd.RDD[(String, Iterable[Int])] = MappedValuesRDD[11] at groupByKey at <console>:14
scala> val rdd3 = rdd2.map( tup => (tup._1 , tup._2.sum/tup._2.size) )
scala> val col2 = rdd3.collect
col2: Array[(String, Int)] = Array((k1,1), (k2,2), (k3,3))
scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",22),("k2",24),("k3",13),("k3",23),("k3",33)) )
scala> val col1 = rdd1.groupByKey().map( tup => (tup._1 , tup._2.sum / tup._2.size) ).collect
col1: Array[(String, Int)] = Array((k1,15), (k2,23), (k3,23))

Actions

The following table lists some of the common actions supported by Spark. Refer to the RDD API doc (Scala, Java, Python) and pair RDD functions doc (Scala, Java) for details.
def collect(): Array[T]
Return an array that contains all of the elements in this RDD.

Return all the elements of the dataset as an array at the driver program. This is usually useful after a filter or other operation that returns a sufficiently small subset of the data.

org.apache.spark.rdd.PairRDDFunctions

def collectAsMap(): Map[K, V]
Return the key-value pairs in this RDD to the master as a Map.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)))
scala> val rdd3 = rdd1.collectAsMap()
...
14/06/20 18:53:56 INFO SparkContext: Job finished: collectAsMap at <console>:14, took 2.196388914 s
rdd3: scala.collection.Map[String,Int] = Map(k2 -> 14, k4 -> 19, k1 -> 15, k3 -> 18)

def count(): Long
Return the number of elements in the RDD.

Return the number of elements in the dataset.

org.apache.spark.rdd.PairRDDFunctions

def countByKey(): Map[K, Long]
Count the number of elements for each key, and return the result to the master as a Map.

Only available on RDDs of type (K, V). Returns a hashmap of (K, Int) pairs with the count of each key.

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)))
scala> val rdd3 = rdd1.countByKey()
...
14/06/18 10:03:45 INFO SparkContext: Job finished: countByKey at <console>:15, took 2.508177768 s
res0: scala.collection.Map[String,Long] = Map(k2 -> 2, k4 -> 1, k1 -> 1, k3 -> 3)
def first(): T
Return the first element in this RDD.

Return the first element of the dataset (similar to take(1)).
def fold(zeroValue: T)(op: (T, T) ⇒ T): T
Aggregate the elements of each partition, and then the results for all the partitions, using a given associative function and a neutral "zero value". The function op(t1, t2) is allowed to modify t1 and return it as its result value to avoid object allocation; however, it should not modify t2.
@@傳入函式op(t1, t2), 其中t1為上次運算結果result value, t2為RDD成員, 起始值zeroValue必須是RDD成員型態T

scala> val rdd1 = sc.parallelize( 1 to 9, 3)
scala> val rdd3 = rdd1.fold(0)((x,y) => {
 println("x=["+x+"] y=["+y+"]")
 x+y
})
14/06/18 14:09:26 INFO DAGScheduler: Completed ResultTask(1, 1)
x=[0] y=[15]  // 1st參數為起始參數, 2nd參數為自己partition的運算結果 (4+5+6)
14/06/18 14:09:26 INFO DAGScheduler: Completed ResultTask(1, 0)
x=[15] y=[6]  // 1st參數前一次運算結果, 2nd參數為自己partition的運算結果 (1+2+3)
14/06/18 14:09:27 INFO DAGScheduler: Completed ResultTask(1, 2)
x=[21] y=[24] // 1st參數前一次運算結果, 2nd參數為自己partition的運算結果 (7+8+9)
14/06/18 14:09:27 INFO SparkContext: Job finished: fold at <console>:14, took 0.530989185 s
rdd3: Int = 45

@@起始變數與最終結果型態必須是RDD的成員型態
scala> val rdd3 = rdd1.fold("(")((x,y) => {
 println("x=["+x+"] y=["+y+"]")
 x+y+","
})
<console>:14: error: type mismatch;
found   : String("(")
required: Int
      val rdd3 = rdd1.fold("(")((x,y) => {
                           ^
def foreach(f: (T) ⇒ Unit): Unit
Applies a function f to all elements of this RDD.

foreach(func)
Run a function func on each element of the dataset. This is usually done for side effects such as updating an accumulator variable (see below) or interacting with external storage systems.
def max()(implicit ord: Ordering[T]): T
Returns the max of this RDD as defined by the implicit Ordering[T].

scala> val rdd1 = sc.parallelize( 1 to 1000000000)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:12
scala> val rdd3 = rdd1.max()
...
14/06/18 16:30:44 INFO SparkContext: Job finished: max at <console>:14, took 10.16371266 s
rdd3: Int = 1000000000

org.apache.spark.rdd.DoubleRDDFunctions

def mean(): Double
Compute the mean of this RDD's elements.

@@restart spark-shell
scala> val rdd1 = sc.parallelize( 1 to 1000000000)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[5] at parallelize at <console>:12
scala> val rdd3 = rdd1.mean()
14/06/17 14:03:52 INFO SparkContext: Starting job: mean at <console>:14
14/06/17 14:03:52 INFO DAGScheduler: Got job 0 (mean at <console>:14) with 72 output partitions (allowLocal=false)
14/06/17 14:03:52 INFO DAGScheduler: Final stage: Stage 0(mean at <console>:14)
14/06/17 14:03:52 INFO DAGScheduler: Parents of final stage: List()
14/06/17 14:03:52 INFO DAGScheduler: Missing parents: List()
14/06/17 14:03:52 INFO DAGScheduler: Submitting Stage 0 (MapPartitionsRDD[2] at mean at <console>:14), which has no missing parents
14/06/17 14:03:53 INFO DAGScheduler: Submitting 72 missing tasks from Stage 0 (MapPartitionsRDD[2] at mean at <console>:14)
14/06/17 14:03:53 INFO TaskSchedulerImpl: Adding task set 0.0 with 72 tasks
...
14/06/17 14:04:00 INFO SparkContext: Job finished: mean at <console>:14, took 7.341507515 s
rdd3: Double = 5.0000000050000006E8

@@restart spark-shell
scala> val rdd1 = sc.parallelize( 1 to 1000000000, 3)
scala> val rdd3 = rdd1.mean()
14/06/17 15:05:14 INFO SparkContext: Starting job: mean at <console>:14
14/06/17 15:05:14 INFO DAGScheduler: Got job 0 (mean at <console>:14) with 3 output partitions (allowLocal=false)
14/06/17 15:05:14 INFO DAGScheduler: Final stage: Stage 0(mean at <console>:14)
14/06/17 15:05:14 INFO DAGScheduler: Parents of final stage: List()
14/06/17 15:05:14 INFO DAGScheduler: Missing parents: List()
14/06/17 15:05:14 INFO DAGScheduler: Submitting Stage 0 (MapPartitionsRDD[2] at mean at <console>:14), which has no missing parents
14/06/17 15:05:14 INFO DAGScheduler: Submitting 3 missing tasks from Stage 0 (MapPartitionsRDD[2] at mean at <console>:14)
14/06/17 15:05:14 INFO TaskSchedulerImpl: Adding task set 0.0 with 3 tasks
...
14/06/17 15:05:27 INFO SparkContext: Job finished: mean at <console>:14, took 13.088206102 s
rdd3: Double = 5.000000005E8
...

def meanApprox(timeout: Long, confidence: Double = 0.95): PartialResult[BoundedDouble]
Approximate operation to return the mean within a timeout.

@@restart spark-shell
scala> val rdd1 = sc.parallelize( 1 to 1000000000)
scala> val rdd3 = rdd1.meanApprox(2)
14/06/17 15:08:16 INFO SparkContext: Starting job: meanApprox at <console>:14
14/06/17 15:08:16 INFO SparkContext: Job finished: meanApprox at <console>:14, took 0.004457033 s
rdd3: org.apache.spark.partial.PartialResult[org.apache.spark.partial.BoundedDouble] = (partial: [-Infinity, Infinity])

scala> 14/06/17 15:08:16 INFO DAGScheduler: Got job 0 (meanApprox at <console>:14) with 72 output partitions (allowLocal=false)
14/06/17 15:08:16 INFO DAGScheduler: Final stage: Stage 0(meanApprox at <console>:14)
14/06/17 15:08:16 INFO DAGScheduler: Parents of final stage: List()
14/06/17 15:08:16 INFO DAGScheduler: Missing parents: List()
14/06/17 15:08:16 INFO DAGScheduler: Submitting Stage 0 (MappedRDD[1] at numericRDDToDoubleRDDFunctions at <console>:14), which has no missing parents
14/06/17 15:08:16 INFO DAGScheduler: Submitting 72 missing tasks from Stage 0 (MappedRDD[1] at numericRDDToDoubleRDDFunctions at <console>:14)
14/06/17 15:08:16 INFO TaskSchedulerImpl: Adding task set 0.0 with 72 tasks
...
14/06/17 15:08:24 INFO DAGScheduler: Stage 0 (meanApprox at <console>:14) finished in 7.460 s
scala> rdd3.toString
res1: String = (final: [500000000.500, 500000000.500])
@@restart spark-shell
scala> val rdd1 = sc.parallelize( 1 to 1000000000)
scala> val rdd3 = rdd1.meanApprox(2,0.8)
...
14/06/17 15:15:19 INFO DAGScheduler: Stage 0 (meanApprox at <console>:14) finished in 8.560 s
scala> rdd3.toString
res0: String = (final: [500000000.500, 500000000.500])
def min()(implicit ord: Ordering[T]): T
Returns the min of this RDD as defined by the implicit Ordering[T].

scala> val rdd1 = sc.parallelize( 1 to 1000000000)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:12
scala> val rdd3 = rdd1.min()
...
14/06/18 16:31:32 INFO SparkContext: Job finished: min at <console>:14, took 3.024976804 s
rdd3: Int = 1
def reduce(f: (T, T) ⇒ T): T
Reduces the elements of this RDD using the specified commutative and associative binary operator.

Aggregate the elements of the dataset using a function func (which takes two arguments and returns one). The function should be commutative and associative so that it can be computed correctly in parallel.

scala> val rdd1 = sc.parallelize( 1 to 9)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[4] at parallelize at <console>:12
scala> val rdd3 = rdd1.reduce(_+_)
...
14/06/17 15:27:59 INFO SparkContext: Job finished: reduce at <console>:14, took 0.138111262 s
rdd3: Int = 45
.
def saveAsObjectFile(path: String): Unit
Save this RDD as a SequenceFile of serialized objects.

Write the elements of the dataset in a simple format using Java serialization, which can then be loaded usingSparkContext.objectFile().

org.apache.spark.rdd.SequenceFileRDDFunctions

def saveAsSequenceFile(path: String, codec: Option[Class[_ <: CompressionCodec]] = None): Unit
Output the RDD as a Hadoop SequenceFile using the Writable types we infer from the RDD's key and value types. If the key or value are Writable, then we use their classes directly; otherwise we map primitive types such as Int and Double to IntWritable, DoubleWritable, etc, byte arrays to BytesWritable, and Strings to Text. The path can be on any Hadoop-supported file system.

Write the elements of the dataset as a Hadoop SequenceFile in a given path in the local filesystem, HDFS or any other Hadoop-supported file system. This is available on RDDs of key-value pairs that either implement Hadoop's Writable interface. In Scala, it is also available on types that are implicitly convertible to Writable (Spark includes conversions for basic types like Int, Double, String, etc).
def saveAsTextFile(path: String, codec: Class[_ <: CompressionCodec]): Unit
Save this RDD as a compressed text file, using string representations of elements.

def saveAsTextFile(path: String): Unit
Save this RDD as a text file, using string representations of elements.

Write the elements of the dataset as a text file (or set of text files) in a given directory in the local filesystem, HDFS or any other Hadoop-supported file system. Spark will call toString on each element to convert it to a line of text in the file.
def stats(): StatCounter
Return a org.apache.spark.util.StatCounter object that captures the mean, variance and count of the RDD's elements in one operation.
@@參考sample()函式範例
def take(num: Int): Array[T]
Take the first num elements of the RDD. It works by first scanning one partition, and use the results from that partition to estimate the number of additional partitions needed to satisfy the limit.

Return an array with the first n elements of the dataset. Note that this is currently not executed in parallel. Instead, the driver program computes all the elements.
@@傳回Array, 成員型態為RDD的成員型態

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)), 3)
scala> val rdd3 = rdd1.take(3)
...
14/06/18 14:38:08 INFO SparkContext: Job finished: take at <console>:14, took 1.121084616 s
rdd3: Array[(String, Int)] = Array((k1,15), (k2,12), (k2,14))
scala> rdd3(2)
res2: (String, Int) = (k2,14).
def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]
Returns the first K (smallest) elements from this RDD as defined by the specified implicit Ordering[T] and maintains the ordering. This does the opposite of top. For example:
sc.parallelize([10, 4, 2, 12, 3]).takeOrdered(1)
// returns [12]

sc.parallelize([2, 3, 4, 5, 6]).takeOrdered(2)
// returns [2, 3]
num : the number of top elements to return
ord : the implicit ordering for T
returns : an array of top elements

Return the first n elements of the RDD using either their natural order or a custom comparator. @@排序後從最小值開始取num個成員, 傳回Array

scala> val rdd1 = sc.parallelize( List(("k1",15),("k2",12),("k2",14),("k3",13),("k3",15),("k3",18),("k4",19)), 3)
scala> val rdd3 = rdd1.takeOrdered(2)
...
14/06/18 15:15:37 INFO SparkContext: Job finished: takeOrdered at <console>:14, took 0.094343614 s
rdd3: Array[(String, Int)] = Array((k1,15), (k2,12))
def takeSample(withReplacement: Boolean, num: Int, seed: Long = Utils.random.nextLong): Array[T]

Return an array with a random sample of num elements of the dataset, with or without replacement, using the given random number generator seed.
core/src/main/scala/org/apache/spark/rdd/RDD.scala
@@withR=true => use PoissonSampler, withR=false => BernoulliSampler

scala> val rdd1 = sc.parallelize( 1 to 9999, 3)
scala> val rdd3 = rdd1.takeSample(true, 10)
...
14/06/18 15:39:00 INFO SparkContext: Job finished: takeSample at <console>:14, took 0.073171104 s
rdd3: Array[Int] = Array(4817, 3734, 6030, 6532, 9037, 4544, 2236, 5960, 5691, 403)
def top(num: Int)(implicit ord: Ordering[T]): Array[T]
Returns the top K (largest) elements from this RDD as defined by the specified implicit Ordering[T]. This does the opposite of takeOrdered. For example:
sc.parallelize([10, 4, 2, 12, 3]).top(1)
// returns [12]

sc.parallelize([2, 3, 4, 5, 6]).top(2)
// returns [6, 5]
num : the number of top elements to return
ord : the implicit ordering for T
returns : an array of top elements