import org.apache.spark.{SparkContext, SparkConf}
object Ex4_MoreOperationsOnRDDs {
def main(args: Array[String]) {
val conf = new SparkConf().setAppName("Ex4_MoreOperationsOnRDDs").setMaster("local[4]")
val sc = new SparkContext(conf)
/**
* 制造RDD
*/
val letters = sc.parallelize('a' to 'z', 8)
// vowels, but NOT an RDD
// this is important because you can't access RDDs in
// operations on individual elements of an RDD
val vowels = Seq('a', 'e', 'i', 'o', 'u')
/**
* 找出所有不在c中的值,这个本身很简单,代码不难,但是这里有个思想,就是val变量
* val变量表示不可变变量,他的优势就在于在分布式系统中可以放心的使用这个变量而不需要考虑
* 并发冲突问题,而这也是整个函数式编程的思想,创建无副作用的函数
*/
val consonants = letters.filter(c => !vowels.contains(c))
println("There are " + consonants.count() + " consonants")
/**
* 以下为原版写法,由于这样的写法不易于理解,我另写一个写法
* 熟悉那种用哪种,他这种写法更简便
*/
val consonantsAsDigits = letters collect {
case c:Char if !vowels.contains(c) => c.asDigit
}
consonantsAsDigits.foreach(println)
val consonantsAsDigits2 = letters.collect().filter(!vowels.contains(_)).map(_.asDigit)
consonantsAsDigits2.foreach(println)
/**
* 这里主要说的是flatMap,这个函数比较简单,网上说这个功能是扁平化,其实从源代码角度来说就是生成了个新的iterator
* spark的flatMap是在每个MapPartitionsRDD中调用scala原生的flatMap实现的,所以看明白原生的flatMap就能明白spark如何实现的
* 1、scala源码
* def flatMap[B](f: A => GenTraversableOnce[B]): Iterator[B] = new AbstractIterator[B] {
* private var cur: Iterator[B] = empty
* private def nextCur() { cur = f(self.next()).toIterator }
* def hasNext: Boolean = {
* // Equivalent to cur.hasNext || self.hasNext && { nextCur(); hasNext }
* // but slightly shorter bytecode (better JVM inlining!)
* while (!cur.hasNext) {
* if (!self.hasNext) return false
* nextCur()
* }
* true
* }
* def next(): B = (if (hasNext) cur else empty).next()
* }
*
* cur代表新的iterator,self代表spark中原始值的迭代器,所以上面代码很简单,通过调用hasNext的时候,通过传入的f方法将
* self迭代器生成新的cur迭代器,然后操作cur迭代器
* 2、f方法
*
* def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U] = withScope {
* val cleanF = sc.clean(f)
* new MapPartitionsRDD[U, T](this, (context, pid, iter) => iter.flatMap(cleanF))
* }
* f方法是w => w.iterator方法
*
* 这里面有个比较难理解的东西sc.clean(f),这个方法在很多地方都有用,我详细讲讲这个方法的作用
* 1、闭包以及scala中的闭包
* def main(args: Array[String]): Unit = {
* println("func1:" + func1())
* println("func2:" + func2())
* }
*
* def func1(): Int = {
* def func_inner(i: Int): Int = {
* if (i == 0) return -1
* return i+1
* }
* func_map(func_inner)
* }
*
*
* def func2(): Int ={
* val func_Inner: Int => Int = i => {
* if (i == 0) return -1
* return i+1
* }
* func_map(func_Inner)
* }
*
* def func_map(f: Int => Int): Int = {
* 0 to 10 map f sum
* }
*
* 这里其实和函数的柯里化很像,前面讲过函数柯里化这里就不说了
* 上面这个类是有问题的,他返回了如下值
* func1:64
* func2:-1
* 这个得用另一个专题讲,比较难于理解,请看Ex10_Closure的相关讲解
*
*/
val words = sc.parallelize(Seq("Hello", "World"), 2)
val chars = words.flatMap(w => w.iterator)
println(chars.map(c => c.toString).reduce((s1, s2) => s1 + " " + s2))
/**
* 按照3的余数分组然后打印
*/
// groupBy
val numbers = sc.parallelize(1 to 10, 4)
val modThreeGroups = numbers.groupBy(_ % 3)
// Note: pair RDDs are special in Spark
modThreeGroups foreach {
case (m, vals) => println("mod 3 = " + m + ", count = " + vals.count(_ => true))
}
/**
* 查找每个余数的出现次数
*/
val mods = modThreeGroups.collect({
case (m, vals) => vals.count(_ => true) }).countByValue
println("results found 3 times: " + mods.get(3))
println("results found 4 times: " + mods.get(4))
println("results found 7 times: " + mods.get(7))
// 取最大值或者最小值
println("maximum element = " + letters.max())
// 取第一个
println("first element = " + letters.first())
// 返回此RDD的抽样子集。
println("random [fractional] sample without replacement: ")
val samp = letters.sample(false, 0.25, 42)
samp.foreach(println)
//排序
// TODO: this deserves a clearer example of how spiffy it is
println("first element when reversed = " + letters.sortBy(v => v, false).first())
// 取前N个
println("first five letters:")
val first5 = letters.take(5)
first5.foreach(println)
//随机5个字母,不替换
println("random five letters without replacement:")
val random5 = letters.takeSample(false, 5)
random5.foreach(println)
}
}
Githup项目LearningSpark代码讲解(五)
最新推荐文章于 2024-07-20 01:01:27 发布