Spark之RDD使用详解

一、创建

1.外部数据源

(1)读取win读取win (读取多个文件)

val conf=new SparkConf().setAppName("New Test").setMaster("local")
val sc=new SparkContext(conf)

val readText=sc.textFile("D:\\example\\1.txt,D:\\example\\2.txt")
val result=readText.saveAsTextFile("D:\\all\\result")

(2)加载HDFS保存Linux (含通配符的路径)

  val conf=new SparkConf().setAppName("wordcount")
  val sc=new SparkContext(conf)

  val input=sc.textFile("hdfs://master:9000/hive/*.txt")
  val lines=input.flatMap(line=>line.split(" "))
  val count=lines.map(word=>(word,1)).reduceByKey{case (x,y)=>x+y}
  val output=count.saveAsTextFile("file:///data1/test/result")

(3)加载HDFS保存HDFS

  val conf=new SparkConf().setAppName("cal_wel")
  val sc=new SparkContext(conf)

  val rdd=sc.textFile("hdfs://master:9000/hive/order_20200105.txt");
  val rdd1=rdd.map(line=>(line.split("\t")(1),1)).reduceByKey((x,y)=>x+y)
  rdd1.repartition(1).saveAsTextFile("hdfs://master:9000/tmp/result")

二、算子

1.Transformation

map(func) 返回一个新RDD。该RDD由每一个输入元素经过func函数转换后组成
filter(func) 返回一个新RDD。该RDD由经过func函数计算后返回值为true的输入元素组成
flatMap(func) 类似map,但每一个输入元素可以被映射为0或多个输出元素

distinct([numTasks])

对源RDD进行去重后返回一个新RDD
union(otherDataset) 对源RDD和参数RDD求并集后返回一个新RDD
join(otherDataset,[numTasks]) 在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD,相当于内连接
leftOuterJoin 类上,左连接
rightOuterJoin 类上,右连接
groupByKey([numTasks]) 在一个(K,V)的RDD上调用,返回一个(K,Iterator[V])的RDD
reduceByKey(func,[numTasks]) 在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定迭代reduce函数,将相同key的值聚合到一起,与groupBy类似。reduce任务的个数可以通过第2个可选参数来设置
sortByKey([ascending],[numTasks]) 在一个(K,V)的RDD上,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD
combineByKey 合并相同的key值,将RDD[K,V]转化为RDD[K,C]
mapValues(func) 在一个(K,V)的RDD上,key不变,对每个value都应用func函数
persist RDD缓存,可避免重复计算从而减少时间,可选择缓存级别
cache RDD缓存,可避免重复计算从而减少时间,cache内部调用了persist算子,cache摩恩只有一个缓存级别MEMORY-ONLY
sample(withReplacement,fraction,seed) 根据fraction指定的比例对数据进行采样,可以选择是否使用随机数进行替换,seed用于指定随机数生成器种子
coalesce(numPartitions,shuffle) 重新分区。第1个参数分为多少区,第2个参数是否shuffle
repartition(numPartitions) 重新分区,调用coalesce且第2个参数为true的实现

2.Action

collect 返回RDD中的所有元素 rdd.collect()
foreach(func) 对RDD中的每个元素使用给定的函数 rdd.foreach(func)
count RDD中的元素个数 rdd.count()
reduce(func) 并行整合RDD中所有元素 rdd.reduce((x,y)=>x+y)
take(num) 从RDD中返回前num个元素 rdd.take(2)
takeSample(withReplacement, num, [seed]) 从RDD返回任意一些元素 rdd.takeSample(false, 1)
top(num) 从RDD中返回最前面的num个元素 rdd.top(2)
countByValue 各元素在RDD中出现的次数  rdd.countByValue()
takeOrdered(num) 从RDD中按照提供的顺序返回最前面的num个元素 rdd.takeOrdered(2)
fold(0)(func) 和reduce一样,但需要提供初始值 rdd.fold(0)((x,y)=> x+y)
aggregate(zeroValue)(seqOp, combOp) 类似reduce,但通常返回不同类型函数 rdd.aggregate((0,0))(      (x,y)=>(x._1+y,x._2+1),      (x,y)=>(x._1+y._1,x._2+y._2))
first 返回第1个元素 rdd.first()
sum 总和 rdd.sum()

三、应用

1.map

       对RDD中的每个元素都执行一个指定的函数来产生一个新的RDD。

       返回值:RDD

  • 示例
  def map1(sc:SparkContext):Unit={
     val rdd=sc.parallelize(List(1,2,3,4))
     val rdd1=rdd.map(line=>line+1)
     rdd1.foreach(println)
  }

  def map2(sc:SparkContext):Unit={
     val rdd=sc.parallelize(List(("spark",0),("hadoop",10),("hadoop",4),("spark",4)))
     val mapRdd=rdd.map(line=>(line,1))
     mapRdd.foreach(println)
  }

  def map3(sc:SparkContext):Unit={
     val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\movies.csv")
     val arr=rdd.map(line=>line.split(",")).collect()
     for(i <- 0 to 2){
       for(j <- 0 to 2){
          print(arr(i)(j)+"\t")
       }
       println()
     }
  }

2.filter

       对RDD元素进行过滤,返回一个新的数据集。(经过func函数后返回值为true的原元素组成)

       返回值:RDD

  • 示例
  def filter1(sc:SparkContext):Unit={
     val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\movies.csv")
     val filterRdd=rdd.filter(line=>line.contains("Drama"))
     filterRdd.foreach(println)
  }

  def filter2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(1,2,3,7,4,5,8))
    val filterRdd=rdd.filter(x=>x>=4)
    filterRdd.foreach(println)
  }

3.flatMap

        类似map,但对每一个输入元素,会被映射为0到多个输出元素

        而mapPartitions的输入函数是每个分区的数据,也就是把每个 分区的内容作为整体来处理的。

  • 示例
​
  def flatMap1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(1 to 10,3)
    rdd.foreach(println)
  }


  def flatMap2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A",1),("B",2),("C",3)))
    rdd.flatMap(x=>(x._1+x._2)).foreach(println)
  }

4.mapPartitions

        mapPartitions是map的一个变种。可看作先对RDD进行partition,再把每个partition进行map函数。

        map的输入函数是应用于RDD中每个元素,而mapPartitions的输入函数是每个分区的数据。

        即把每个分区中的内容作为整体来处理的

  • 应用场景
当数据量不太大的时候,可以用mapPartitions,可以提高运行效率;
当数据量太大的时候,有可能会发生oom
  • 示例
  def mapPartitions1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(1,2,3,4,5,6), 2)
    val mapPartitionsRdd=rdd.mapPartitions(_.map(_+1))
    mapPartitionsRdd.foreach(println)
  }

  
  def doubleFunc(iter:Iterator[Int]): Iterator[(Int,Int)]={
    var res=List[(Int,Int)]()
    while(iter.hasNext){
      val cur=iter.next
      res.::=(cur, cur*2)
    }
    res.iterator
  }
  def mapPartitions2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(1 to 9, 3)
    val mapPartitionsRdd=rdd.mapPartitions(doubleFunc)
    println(mapPartitionsRdd.collect().mkString)
  }

  
  def menaFunc(iter:Iterator[Int]):Iterator[(Int,Int)]={
    var x,y=0
    var res=List[(Int,Int)]()
    while(iter.hasNext){
      val cur=iter.next
      x+=cur
      y+=1
    }
    res.::=(x,y)
    res.iterator
  }
  def reduceFunc(x:(Int,Int),y:(Int,Int)):(Int,Int)={
    (x._1+y._1, x._2+y._2)
  }
  def mapPartitions3(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(1,2,3,4),3)
    val sum=rdd.mapPartitions(menaFunc).reduce(reduceFunc)
    println(sum._1/sum._2.asInstanceOf[Float])
  }

5.mapPartitionsWithIndex

        mapPartitionsWithSplit与mapPartitions的功能类似,只是多传入split index而已。

        所有func函数必须是(Int,Iterator<T>)=>Iterator<U>类型

  • 示例
  def func(index:Int, it:Iterator[Int]):Iterator[String]={
    it.map(x=>s"part:$index, ele:$x")
  }
  def mapPartitionsWithIndex1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(1,2,3,4,5,6),2)
    val mapPartitionsWithIndexRdd=rdd.mapPartitionsWithIndex(func)
    mapPartitionsWithIndexRdd.foreach(println)
  }

  def mapPartitionsWithIndex2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("tom1","tom2","tom3","tom4","tom5","tom6"),3)
    val mapPartitionsWithIndexRdd=rdd.mapPartitionsWithIndex((index,x)=>{
      val list=ListBuffer[String]()
      while(x.hasNext){
        list+="part:"+index+", ele:"+x.next
      }
      list.iterator
    })
    mapPartitionsWithIndexRdd.foreach(println)
  }

6.sample

        sample (withReplacement,fraction,seed)是根据给定的随机种子seed,随机抽样出数量为frac的数据。

        withReplacement:是否放回抽样

        fraction:比例。比如0.1表示10%

        seed:随机种子

        返回值:RDD

  • 示例
  def sample1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(2,3,7,4,8))
    val sampleRdd=rdd.sample(false,0.5)
    sampleRdd.foreach(println)
  }

  def sample2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(2,3,7,4,8))
    val sampleRdd=rdd.sample(true,2)
    sampleRdd.foreach(println)
  }

  def sample3(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List(1,2,3,7,4,5,8))
    val sampleRdd=rdd.sample(false,0.25,System.currentTimeMillis())
    sampleRdd.foreach(println)
  }

7.union

        union(otherDataset)是数据合并,返回一个新的数据集,又原数据集和otherDataset联合而成。

        返回值:RDD

  • 示例
  def union1(sc:SparkContext):Unit={
    val rdd1=sc.makeRDD(List("张三","李四"))
    val rdd2=sc.makeRDD(List("tom","marry"))
    val unionRdd=rdd1.union(rdd2)
    unionRdd.foreach(println)
  }

8.intersection

        intersection(otherDataset)是数据交集,返回一个新的数据集。(两个数据集的交集数据)。

        返回值:RDD

  • 示例
  def intersection1(sc:SparkContext):Unit={
    val rdd1=sc.makeRDD(List("张三","李四","王五","tom"))
    val rdd2=sc.makeRDD(List("tom","lilei"))
    val intersectionRdd=rdd1.intersection(rdd2)
    intersectionRdd.foreach(println)
  }

9.distinct

        distinct([numTasks])是数据去重,返回一个数据集,是对连个数据集去除重复数据

        numTasks是设置任务并行数量

  • 示例
  def distinct1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List("张三","李四","王五","李四","王五"))
    val distinctRdd=rdd.distinct()
    distinctRdd.foreach(println)
  }

10.groupByKey

          groupByKey([numTasks])是数据分组操作,在一个由(K,V)对组成的数据集上调用,返回一个(K,Seq[V])对的数据集。

          返回值:RDD[ Tuple2[K,Iterable[V]] ]

  • 示例
def groupByKey1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("one","two","three","three","three","one"))
    val mapRdd=rdd.map(line=>(line,1))
    val groupByKeyRdd=mapRdd.groupByKey()
    groupByKeyRdd.foreach(println)
  }

  def groupByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A",0),("A",2),("B",1),("B",8),("C",3)))
    val groupByKeyRdd=rdd.groupByKey()
    groupByKeyRdd.foreach(println)
  }

11.reduceByKey

         reduceByKey(func,[numTasks])是一个(K,V)对的数据集上使用,返回一个(K,V)的数据集。

         key相同的值,都被使用指定的reduce函数聚合到一起。

         返回值:RDD[ Tuple2[K, V] ]

  • 示例
  def reduceByKey1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Array(("A",0),("A",2),("B",3),("B",4),("C",6)))
    val reduceByKeyRdd=rdd.reduceByKey((x,y)=>x+y)
    reduceByKeyRdd.foreach(println)
  }

  def reduceByKey2(sc:SparkContext):Unit={
    val rdd=sc.textFile(Constant.LoCAL_FILE_PREX+"/data/rdd/wordData.log")
    println(Constant.LoCAL_FILE_PREX)
    val reduceByKeyRdd=rdd.flatMap(line=>line.split("\\s+")).map(x=>(x,1)).reduceByKey((x,y)=>x+y)
    reduceByKeyRdd.foreach(println)
  }

12.aggreateByKey

        aggreateByKey和reduceByKey的不同之处在于,reduceByKey输入输出都是(K,V),而aggreateByKey输出是(K,U)

        aggreateByKey的3个参数:

            zeroValue:U,初始值,比如空列表{}

            seqOp:(U,T)=>U,seq操作符,描述如何将T合并如U,比如如何将item合并到列表

            combOp:(U,T)=>U,comb操作符,描述如何合并两个U,比如合并两个列表

        所以aggreateByKey可以看成更高抽象的,更灵活的reduce或group

  • 示例
  def aggregateByKey1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(("cat",3), ("cat", 1), ("mouse", 4), ("dog", 9), ("mouse", 2)),2)
    val aggregateByKeyRdd=rdd.aggregateByKey(100)(_+_, _+_)
    aggregateByKeyRdd.foreach(println)
  }

  def combOp(a:List[Int], b:List[Int]):List[Int]={
    a.:::(b)
  }
  def seqOp(a:List[Int], b:Int):List[Int]={
    a.::(b)
  }
  def aggregateByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List((1,3),(1,2),(1,4),(2,3)))
    val aggregateByKeyRdd=rdd.aggregateByKey(List[Int]())(seqOp,combOp)
    aggregateByKeyRdd.foreach(println)
  }

13.combineByKey

       对RDD中的数据集按照Key进行聚合操作,聚合操作的逻辑是通过自定义函数提供给combineByKey。

  • 参数
combineByKey[C](createCombiner: (V) ⇒ C, mergeValue: (C, V) ⇒ C, mergeCombiners: (C, C) ⇒ C, numPartitions: Int):RDD[(K, C)]


(1) combinByKey会遍历rdd中每一个(k,v)数据对,对该数据对中的k进行判断,判断该(k,v)对中的k是否在之前出现过,如果是第一次出现,则调用createCombiner函数,对该k对应的v进行初始化操作

(2)作用在每一个分区内部,将V合并到之前(createCombiner)的元素上

(3)当所有的分区内的数据计算完成之后,开始调用mergeCombiners函数,对每个分区的数据进行合并
  • 示例
  def combineByKey1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Array(("A",1),("A",2),("B",3),("B",4),("C",6)))
    val combineByKeyRdd=rdd.combineByKey((v:Int)=>v+"-",(c:String,v:Int)=>c+"@"+v,(c1:String,c2:String)=>c1+"$"+c2)
    combineByKeyRdd.foreach(println)
  }

  def combineByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array((1, 1.0), (1, 2.0), (1, 3.0), (2, 4.0), (2, 5.0), (2, 6.0)))
    val combineByKeyRdd=rdd.combineByKey((v:Double)=>(v,1), (c:(Double,Int),v:Double)=>(c._1+v,c._2+1),(c1:(Double,Int),c2:(Double,Int))=>(c1._1+c2._1, c1._2+c2._2))
    combineByKeyRdd.foreach(println)
  }

  def combineByKey3(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(("A", 3), ("A", 9), ("A", 12),("B", 4), ("B", 10), ("B", 11)), 2)
    val combineByKeyRdd=rdd.combineByKey(
      (x:Int)=>(x,1),
      (acc:(Int,Int), x)=>(acc._1+x, acc._2+1),
      (p1:(Int,Int), p2:(Int,Int))=> (p1._1+p2._1, p1._2+p2._2)
    )
    combineByKeyRdd.foreach(println)
  }

  def combineByKey4(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("coffee",1), ("coffee",2), ("panda",3), ("coffee",9)))
    val combineByKeyRdd=rdd.combineByKey(score=>(1,score), (c:(Int,Int),newScore:Int)=>(c._1+1,c._2+newScore), (c1:(Int,Int),c2:(Int,Int))=>(c1._1+c2._1,c1._2+c2._2))
    val averageRdd=combineByKeyRdd.map{
      //case(key,value)=>(key,value._2/value._1)
      case(name,(num,score))=>(name,score/num)
    }
    averageRdd.foreach(println)
  }

  def combineByKey5(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array((("1","011"),1), (("1","012"),1), (("2","011"),1), (("2","013"),1), (("2","014"),1)))
    val combineByKeyRdd=rdd.map(x=>(x._1._1, (x._1._2,1))).combineByKey(
      (v:(String,Int))=> (v:(String,Int)),
      (acc:(String,Int), v:(String,Int))=> (acc._1+":"+v._1, acc._2+v._2),
      (p1:(String,Int), p2:(String,Int))=> (p1._1+":"+p2._1, p1._2+p2._2)
    )
    combineByKeyRdd.foreach(println)
  }

14.sortByKey

       sortByKey([ascending],[numTasks])是排序操作,对(K,V)类型的数据按照K进行排序,其中K需要实现Ordered方法

       返回值:RDD[ Tuple2[K, V] ]

  • 示例
  def sortByKey1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List((60,"张三"), (70,"李四"), (80,"王五"), (55,"赵六"), (45,"郭七"), (75,"林八")))
    val sortByKeyRdd=rdd.sortByKey()
    sortByKeyRdd.foreach(println)
  }

  def sortByKey2(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List((60,"张三"), (70,"李四"), (80,"王五"), (55,"赵六"), (45,"郭七"), (75,"林八")))
    val sortByKeyRdd=rdd.sortByKey(false) //降序
    sortByKeyRdd.foreach(println)
  }

15.join

        join(otherDataset,[numTasks])是连接操作,讲那个输入数据集(K,V)和另外一个(K,W)进行join,得到(K,(V,W)

        该操作是对于相同K的V和W集合进行笛卡尔积操作,即V和W的所有组合

        连接操作除了join外,还有左连接leftOuterJoin、右连接rightOuterJoin、全连接fullOuterJoin

  • 示例
  def join1(sc:SparkContext):Unit={
    val productRdd=sc.parallelize(List((1,"苹果"),(2,"梨"),(3,"香蕉"),(4,"石榴")))
    val countRdd=sc.parallelize(List((1,7),(2,3),(3,8),(4,3),(5,9)))
    val joinRdd=productRdd.join(countRdd)
    joinRdd.foreach(println)
  }

  def leftOuterJoin1(sc:SparkContext):Unit={
    val productRdd=sc.parallelize(List((1,"苹果"),(2,"梨"),(3,"香蕉"),(4,"石榴")))
    val countRdd=sc.parallelize(List((1,7),(2,3),(3,8),(4,3),(5,9)))
    val joinRdd=productRdd.leftOuterJoin(countRdd)
    joinRdd.foreach(println)
  }

  def rightOuterJoin1(sc:SparkContext):Unit={
    val productRdd=sc.parallelize(List((1,"苹果"),(2,"梨"),(3,"香蕉"),(4,"石榴")))
    val countRdd=sc.parallelize(List((1,7),(2,3),(3,8),(4,3),(5,9)))
    val joinRdd=productRdd.rightOuterJoin(countRdd)
    joinRdd.foreach(println)
  }

16.cogroup

        cogroup(otherDataset,[numTasks])是将输入数据集(K,V)和另外一个数据集(K,W)进行congroup,得到一个格式为(K,Seq[V],Seq[V])的数据集。

        返回值:RDD[ Tuple2[K, Tuple2[ Iterable[V], Iterable[W] ] ] ]

  • 示例
  def cogroup1(sc:SparkContext):Unit={
    val rdd1=sc.parallelize(Array((1,"a"),(2,"b"),(3,"c"),(4,"d")))
    val rdd2=sc.parallelize(Array((1,4),(2,5),(3,6)))
    val cogroupRdd=rdd1.cogroup(rdd2)
    cogroupRdd.foreach(println)
  }

17.cartesian

         cartesian(otherDataset)是做笛卡尔积:对于数据集T和U进行笛卡尔积操作,得到(T,U)格式的数据集

         返回值:RDD[ Tuple2[T, U] ]

  • 示例
  def cartesian1(sc:SparkContext):Unit={
    val rdd1=sc.parallelize(1 to 3)
    val rdd2=sc.parallelize(4 to 6)
    val cartesianRdd=rdd1.cartesian(rdd2)
    cartesianRdd.foreach(println)
  }

18.coalesce

       将RDD进行重分区

  • 示例
  /*
    def coalesce(numPartitions: Int, shuffle: Boolean = false)(implicit ord: Ordering[T] = null): RDD[T]
    参数1:重分区数目
    参数2: 是否进行shuffle,默认false
    功能:将RDD进行重分区,使用HashPartitioner
   */


  def coalesce1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    println("分区数:"+rdd.partitions.size) //13
    val coalesceRdd=rdd.coalesce(2)//减少分区数
    println("新分区数:"+coalesceRdd.partitions.size) //2
    coalesceRdd.saveAsTextFile("E:\\data\\spark\\rdd\\test\\write\\ml-25m")//2
  }

  def coalesce2(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    println("分区数:"+rdd.partitions.size) //13
    val coalesceRdd=rdd.coalesce(20,true)//将shuffle设为true,增加分区数到200
    println("新分区数:"+coalesceRdd.partitions.size) //20
    coalesceRdd.saveAsTextFile("E:\\data\\spark\\rdd\\test\\write\\ml-25m")//20
  }

19.repartition

        将RDD进行重分区,即coalesce函数第2个参数为true的实现

  • 示例
  def repartition1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    println(rdd.getNumPartitions)
    rdd.repartition(1).saveAsTextFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores")
  }

20.persist

       将RDD进行缓存(持久化),可避免重复计算从而减少时间

  • 源码
def persist(newLevel: StorageLevel): this.type = {
  if (storageLevel != StorageLevel.NONE && newLevel != storageLevel) {
    throw new UnsupportedOperationException(
      "Cannot change storage level of an RDD after it was already assigned a level")
  }
  sc.persistRDD(this)
  sc.cleaner.foreach(_.registerRDDForCleanup(this))
  storageLevel = newLevel
  this
}
  • 缓存级别
参数1:useDisk   使用硬盘
参数2:useMemory 使用内存
参数3:useOffHeap使用堆外内存
参数4:反序列化
参数5:备份数

object StorageLevel {
  val NONE = new StorageLevel(false, false, false, false)
  val DISK_ONLY = new StorageLevel(true, false, false, false)
  val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
  val MEMORY_ONLY = new StorageLevel(false, true, false, true)
  val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
  val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
  val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
  val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
  val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
  val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
  val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
  val OFF_HEAP = new StorageLevel(false, false, true, false)
  ......
}

示例:
val MEMORY_AND_DISK_SER_2=new StorageLevel(true,true,false,false,2)
使用该缓存级别的RDD将存储在硬盘以及内存中,使用序列化(在硬盘中),并且在多个节点上备份2份(正常的RDD只有1份)
  • 示例
  def persist1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    rdd.persist(StorageLevel.MEMORY_AND_DISK)
    val count1=rdd.count
    println("count1:"+count1) //耗时10636
    
    val count2=rdd.count
    println("count2:"+count2) //耗时279
    
    val count3=rdd.count
    println("count3:"+count3) //耗时264
  }

21.cache

        将RDD进行缓存(持久化)。内部调用persist,只有一个默认缓存级别MEMORY_ONLY

  • 示例
  def cache1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    rdd.cache()
    val count1=rdd.count
    println("count1:"+count1) //耗时10575
    
    val count2=rdd.count
    println("count2:"+count2) //耗时411
    
    val count3=rdd.count
    println("count3:"+count3) //耗时273
  }

三、Action操作

1.reduce

        reduce(func)是对数据集的所有元素执行聚集func函数,该函数必须是可交换的

        将RDD中元素两两传递给输入函数,同时产生一个新值,新值与RDD中下一个元素再被传递给输入函数直到最后一个值为止

        返回值:T

  • 示例
  def reduce1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List("a","ab","abc","abcd","abcde"))
    val reduceNum=rdd.map(x=>x.length).reduce((x,y)=>x+y)
    println(reduceNum)
  }

  def reduce2(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\app1.log")
    val reduceNum=rdd.map(line=>line.split(" ").size).reduce((a,b)=> if(a>b) a else b)
    println(reduceNum)
  }

2.collect

      将一个RDD转换为数组

       返回值:Array[T]

  • 示例
  def collect1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(1 to 5,4)
    val collectArr=rdd.collect
    for(i <- collectArr)
      println(i)
  }

3.count

      返回数据集中元素的个数

      返回值:Long

  • 示例
  def count1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(1 to 5)
    println(rdd.count())
  }

  def count2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A","1"),("B",2),("C",3)))
    val countNum=rdd.count
    println(countNum)
  }

4.first

      返回数据集中的第一个元素,类似take(1)

      返回值:T

  • 示例
  def first1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(5,4,8,3,0))
    println(rdd.first())
  }

  def first2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("a","ab","abc","abcd"))
    val firstMap=rdd.map(line=>(line,line.length)).first
    println(firstMap)
  }

5.take

      返回一个包含数据集中前n个元素的数组,当前该操作不能并行

      返回值:Array[T]

  • 示例
  def take1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(4,8,3,0,1,9))
    val takeRdd=rdd.take(2)
    takeRdd.foreach(println)
  }

  def take2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("a","ab","abc","abcd"))
    val takeRdd=rdd.map(line=>(line,line.length)).take(3)
    takeRdd.foreach(println)
  }

6.takeOrdered

     takeOrdered(n,[ordering])将RDD中的每个元素进行升序排序后取topN

     返回值:Array[T]

  • 示例
  def takeOrderedTest(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Seq(10,4,2,12,3,1))
    val takeOrderedRdd=rdd.takeOrdered(2)
    takeOrderedRdd.foreach(println)
  }

7.top

    将RDD中的每个元素进行降序排序后取topN

def top(num: Int)(implicit ord: Ordering[T]): Array[T] = withScope {
    takeOrdered(num)(ord.reverse)
}
  • 示例
  def top1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Seq(10,4,2,12,3,1))
    val topRdd=rdd.top(2)
    topRdd.foreach(println)
  }

8.takeSample

     takeSample(withReplacement,num,[seed])返回包含随机的num个元素的数组

     和Sample不同,takeSample是Action操作,因此返回的是数组而不是RDD

     withReplacement:是否有抽样放回

     num:抽取多少个

     返回值:Array[T]

  • 示例
  def takeSample1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(1 to 10)
    val sampleRdd=rdd.takeSample(true,4) //有放回抽样,采取数量4
    sampleRdd.foreach(println)
  }

9.saveAsTextFile

     把数据集中的元素写到一个文本文件,Spark会对每个元素调用toString()方法把每个元素存成文本文件的一行

  • 示例
  def saveAsTextFile1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Seq(("A",1),("B",2),("C",3),("D",4),("E",5),("F",6)),4)
    rdd.saveAsTextFile("E:\\data\\spark\\rdd\\test\\write\\saveAsTextFile")
  }

10.countByKey

      对于(K,V)类型的RDD,返回一个(K,Int)的map,Int为K的个数

  • 示例
  def countByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A","1"),("B",2),("C",3),("A",5)))
    val countByKeyRdd=rdd.countByKey
    countByKeyRdd.foreach(println)
  }

11.foreach

      foreach(func)是对数据集中的每个元素都执行func函数

  • 示例
  def foreach1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A","1"),("B",2),("C",3),("A",5)))
    rdd.foreach(println)
  }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章