spark RDD汇总(一)

collect

	val listRDD = sc.parallelize[Int](Seq(1, 2, 4, 3, 3, 6), 2)

    listRDD.collect() // 收集rdd的所有数据

take

 listRDD.take(2)  // 取前两

top

listRDD.top(2)  // 取最大的两个

first

listRDD.first()  // 取第一个

min

listRDD.min()   // 取最小的

max

class MyOrderingNew extends Ordering[Int] {
  override def compare(x: Int, y: Int): Int = {
    y - x
  }
}
listRDD.max()(new MyOrderingNew)  // 逆序取最大其实就是取最小

takeOrdered

listRDD.takeOrdered(2) //  按照自然顺序找两个
listRDD.takeOrdered(2)(new MyOrderingNew)  // 按照逆序去取两个,其实就是最大的

foreach

listRDD.foreach(x => {  // 应用到每个变量上
      val initNumber = getInitNumber("foreach")
      println(x + initNumber + "==================")
    })

foreachPartition

 // foreach和foreachPartition 这两个和map那两个差不多
    listRDD.foreachPartition(iterator => {
      // 和foreach api的功能是一样,只不过一个是将函数应用到每一条记录,这个是将函数应用到每一个partition
      //如果有一个比较耗时的操作,只需要每一分区执行一次这个操作就行,则用这个函数
      //这个耗时的操作可以是连接数据库等操作,不需要计算每一条时候去连接数据库,一个分区只需连接一次就行
      val initNumber = getInitNumber("foreachPartition")
      iterator.foreach(x => println(x + initNumber + "================="))
    })

reduce

listRDD.reduce((x, y) => x + y)   //各元素相加

treeReduce

// 当分区数据量太多时候,有可能造成最后的计算时,会有各种问题
    // treeReduce 先对部分分区进行累加,再汇总
    listRDD.treeReduce((x, y) => x + y)

fold

//和reduce的功能类似,只不过是在计算每一个分区的时候需要加上初始值1,最后再将每一个分区计算出来的值相加再加上这个初始值
    listRDD.fold(0)((x, y) => x + y)

aggregate

//先初始化一个我们想要的返回的数据类型的初始值
    //然后在每一个分区对每一个元素应用函数一(acc, value) => (acc._1 + value, acc._2 + 1)进行聚合
    //最后将每一个分区生成的数据应用函数(acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)进行聚合
    listRDD.aggregate((0, 0))(
      (acc, value) => (acc._1 + value, acc._2 + 1),
      (acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)
    )

treeAggregate

listRDD.treeAggregate((0, 0))(
      (acc, value) => (acc._1 + value, acc._2 + 1),
      (acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)
    )

broadcast

 val lookupTable = Map("plane" -> "sky", "fish" -> "sea", "people" -> "earth")
// 广播出去
 val lookupTableB = sc.broadcast(lookupTable)
// 获取
val replaceStrOpt = lookupTableB.value.get("plane")

map

// 作用在每一个元素上
val keyValueWordsRDD = wordsRDD.map(word => (word, 1))

reduceByKey

// 对相同的key进行聚合计算
val wordCountRDD = keyValueWordsRDD.reduceByKey((x, y) => x + y)

flatMap

// 将值打平
 val flatMapRDD = listRDD.flatMap(x => x.to(3))
 flatMapRDD.collect()

filter

// 过滤
val filterRDD = listRDD.filter(x => x != 1)
filterRDD.collect()

glom

	//将rdd的每一个分区的数据转成一个数组,进而将所有的分区数据转成一个二维数组
    val glomRDD = listRDD.glom()
    glomRDD.collect() //Array(Array(1, 2), Array(3, 3))

mapPartitions

// 类似于foreachPartition,作用于每一个分区上
val mapPartitionRDD = listRDD.mapPartitions (iterator => {
      //和map api的功能是一样,只不过map是将函数应用到每一条记录,而这个是将函数应用到每一个partition
      //如果有一个比较耗时的操作,只需要每一分区执行一次这个操作就行,则用这个函数
      //这个耗时的操作可以是连接数据库等操作,不需要计算每一条时候去连接数据库,一个分区只需连接一次就行
      val initNumber = getInitNumber("mapPartitions")
      iterator.map(x => x + initNumber)
    })
    mapPartitionRDD.collect()

mapPartitionsWithIndex

val mapPartitionWithIndexRDD = listRDD.mapPartitionsWithIndex((index, iterator) => {
      iterator.map(x => x + index)  // index是第几个分区
    })
    mapPartitionWithIndexRDD.collect()

pipe

//表示执行一个本地脚本(可以是shell,python,java等各种能通过java的Process启动起来的脚本进程)
    //dataRDD的数据就是脚本的输入数据,脚本的输出数据会生成一个RDD即pipeRDD
    val pipeRDD = dataRDD.pipe(Seq("python", "/home/hadoop-jrq/spark-course/echo.py"),
      env, printPipeContext, printRDDElement, false)

    pipeRDD.glom().collect()

textFile

//1: 从一个稳定的存储系统中,比如hdfs文件,或者本地文件系统
    val hdfsFileRDD = sc.textFile("hdfs://master:8020/users/hadoop-jrq/word.txt")
    hdfsFileRDD.count()

range

	val rangeRDD = sc.range(0, 10, 2, 4)
    rangeRDD.collect()

makeRDD

	val makeRDD = sc.makeRDD(Seq(1, 2, 3, 3))
    makeRDD.collect()

parallelize

	val defaultPartitionRDD = sc.parallelize[Int](Seq(1, 2, 3, 3, 4))
    defaultPartitionRDD.partitions

persist

//存储级别:
    //MEMORY_ONLY: 只存在内存中
    //DISK_ONLY: 只存在磁盘中
    //MEMORY_AND_DISK: 先存在内存中,内存不够的话则存在磁盘中
    //OFF_HEAP: 存在堆外内存中
    hdfsFileRDD.persist(StorageLevel.MEMORY_ONLY)
    hdfsFileRDD.getStorageLevel

cache

mapRDD.cache() //表示只存在内存中

unpersist

// 清除存在内存中的数据
mapRDD.unpersist()

sample

	//第一个参数为withReplacement
    //如果withReplacement=true的话表示有放回的抽样,采用泊松抽样算法实现
    //如果withReplacement=false的话表示无放回的抽样,采用伯努利抽样算法实现

    //第二个参数为:fraction,表示每一个元素被抽取为样本的概率,并不是表示需要抽取的数据量的因子
    //比如从100个数据中抽样,fraction=0.2,并不是表示需要抽取100 * 0.2 = 20个数据,
    //而是表示100个元素的被抽取为样本概率为0.2;样本的大小并不是固定的,而是服从二项分布
    //当withReplacement=true的时候fraction>=0
    //当withReplacement=false的时候 0 < fraction < 1

    //第三个参数为:reed表示生成随机数的种子,即根据这个reed为rdd的每一个分区生成一个随机种子
    val sampleRDD = listRDD.sample(false, 0.5, 100)
    sampleRDD.glom().collect()

randomSplit

/按照权重对RDD进行随机抽样切分,有几个权重就切分成几个RDD
    //随机抽样采用伯努利抽样算法实现
    val splitRDD = listRDD.randomSplit(Array(0.2, 0.8))
    splitRDD.size
    splitRDD(0).glom().collect()
    splitRDD(1).glom().collect()

takeSample

//随机抽样指定数量的样本数据
    listRDD.takeSample(false, 1, 100)

sampleByKey

//分层采样
    val fractions = Map(1 -> 0.3, 3 -> 0.6, 5 -> 0.3)
    val sampleByKeyRDD = pairRDD.sampleByKey(true, fractions)
    sampleByKeyRDD.glom().collect()

union

// 连接两个RDD
val thirdRDD = sc.parallelize(Seq(5, 5, 5), 3)
    val unionAllRDD = sc.union(Seq(oneRDD, otherRDD, thirdRDD))
    oneRDD.union(otherRDD).union(thirdRDD).collect()

subtract

// oneRDD 减掉 otherRDD 减掉相同的
    val subtractRDD = oneRDD.subtract(otherRDD)

cartesian

 val cartesianRDD = oneRDD.cartesian(otherRDD)  // 笛卡尔积
    cartesianRDD.collect()

zip

 //要求两个RDD有相同的元素个数, 分区也得是一样的
    val zipRDD = oneRDD.zip(otherRDD)
    zipRDD.collect() // Array[(Int, Int)] = Array((1,3), (2,4), (3,5))

zipPartitions

//要求两个rdd需要有相同的分区数,但是每一个分区可以不需要有相同的元素个数
    val zipPartitionRDD =
      oneRDD.zipPartitions(otherRDD)((iterator1, iterator2)
      => Iterator(iterator1.sum + iterator2.sum))  // 对每个分区进行sum操作
    zipPartitionRDD.collect() // Array[Int] = Array(0, 4, 6, 8)

toDebugString

 mapRDD.toDebugString  // 依赖链

localCheckpoint

mapRDD.localCheckpoint()  // 切断依赖 写入的是内存  速度快,数据的可靠性差

checkpoint

sc.setCheckpointDir("hdfs://master:8020/users/hadoop-jrq/checkpoint")  // 设置路径

    otherMapRDD.checkpoint()  // 此步只是创建了一个目录  使用的是磁盘,数据的可靠性强,速度慢
    otherMapRDD.toDebugString  // 查看依赖

cogroup

//res0: Array[(Int, (Iterable[Int], Iterable[Int]))]
    // = Array((4,(CompactBuffer(),CompactBuffer(5))), (1,(CompactBuffer(2),CompactBuffer())),
    // (5,(CompactBuffer(6),CompactBuffer())), (3,(CompactBuffer(6, 4),CompactBuffer(9))))
    pairRDD.cogroup(otherRDD).collect()

groupWith

//groupWith是cogroup的别名,效果和cogroup一摸一样
    pairRDD.groupWith(otherRDD).collect()

join

// Array[(Int, (Int, Int))] = Array((3,(4,9)), (3,(6,9)))
    pairRDD.join(otherRDD).collect()

leftOuterJoin

// Array[(Int, (Int, Option[Int]))]
    // = Array((1,(2,None)), (5,(6,None)), (3,(4,Some(9))), (3,(6,Some(9))))
    pairRDD.leftOuterJoin(otherRDD).collect()

rightOuterJoin

// Array[(Int, (Option[Int], Int))] = Array((4,(None,5)), (3,(Some(4),9)), (3,(Some(6),9)))
    pairRDD.rightOuterJoin(otherRDD).collect()

fullOuterJoin

// Array[(Int, (Option[Int], Option[Int]))]
    // = Array((4,(None,Some(5))), (1,(Some(2),None)), (5,(Some(6),None)),
    // (3,(Some(4),Some(9))), (3,(Some(6),Some(9))))
    pairRDD.fullOuterJoin(otherRDD).collect()

subtractByKey

// 减掉相同的key, 这个示例减掉了为3的key
    // Array[(Int, Int)] = Array((1,2), (5,6))
    pairRDD.subtractByKey(otherRDD).collect()

combineByKey

 val pairStrRDD = sc.parallelize[(String, Int)](Seq(("coffee", 1),
      ("coffee", 2), ("panda", 3), ("coffee", 9)), 2)
    // 碰到第一个key的时候
    def createCombiner = (value: Int) => (value, 1)
    // 碰到第二个key的时候怎么做
    def mergeValue = {
          // 这里的acc其实就是("coffee", 2) => (2,1) 上面的value是下面的value
      (acc: (Int, Int), value: Int) => (acc._1 + value, acc._2 + 1)
    }
    // 在不同分区里面进行merge
    def mergeCombiners = {
      // 对两个分区里的数据进行合并,acc1代表一个分区
          // 第一个int是它的累加值,后一个是出现的次数
      (acc1: (Int, Int), acc2: (Int, Int)) =>  // (1,1)  (1,2)  => (2,3)
        (acc1._1 + acc2._1, acc1._2 + acc2._2)
    }

    //功能:对pairStrRDD这个RDD统计每一个相同key对应的所有value值的累加值以及这个key出现的次数
    //需要的三个参数:
    //createCombiner: V => C,  ==> Int -> (Int, Int)
    //mergeValue: (C, V) => C,    ==> ((Int, Int), Int) -> (Int, Int)
    //mergeCombiners: (C, C) => C    ==> ((Int, Int), (Int, Int)) -> (Int, Int)
    val testCombineByKeyRDD =
    pairStrRDD.combineByKey(createCombiner, mergeValue, mergeCombiners)
    testCombineByKeyRDD.collect()

count

val numberRDD = sc.parallelize(1 to 10000 , 200)
    //RDD a内容 union 5次,其中有50000个元素
    val numbersRDD = numberRDD ++ numberRDD ++ numberRDD ++ numberRDD ++ numberRDD

    numbersRDD.count()

countApprox countByValueApprox countApproxDistinct countByKeyApprox countByKey countByKeyApprox

 val numberRDD = sc.parallelize(1 to 10000 , 200)
    //RDD a内容 union 5次,其中有50000个元素
    val numbersRDD = numberRDD ++ numberRDD ++ numberRDD ++ numberRDD ++ numberRDD

    numbersRDD.count()

    //第一个参数是超时时间
    //第二个参数是期望达到近似估计的准确度
    // 如果你不断用0.9来调用countApprox,则我们期望90%的结果数据是正确的count值
    //如果count统计在超时时间内执行完,则不会近视估值,而是取正确的值
    //如果count统计在超时时间内没有执行完,则根据执行完的task的返回值和准确度进行近似估值
    val resultCount = numbersRDD.countApprox(200, 0.9)
    resultCount.initialValue.mean
    resultCount.initialValue.low
    resultCount.initialValue.high
    resultCount.initialValue.confidence
    resultCount.getFinalValue().mean

    numbersRDD.countByValue()
    val resultCountValue = numbersRDD.countByValueApprox(200, 0.9)
    resultCountValue.initialValue(1).mean

    //结果是9760,不传参数,默认是0.05
    numbersRDD.countApproxDistinct()
    //结果是9760
    numbersRDD.countApproxDistinct(0.05)
    //8224
    numbersRDD.countApproxDistinct(0.1)
    //10000  参数越小值越精确
    numbersRDD.countApproxDistinct(0.006)

    val pair = sc.parallelize((1 to 10000).zipWithIndex)

    pair.collect()

    val pairFive = pair ++ pair ++ pair ++ pair ++ pair

    pairFive.countByKey()

    pairFive.countByKeyApprox(10, 0.95)

    //用HyperLogLogPlus来实现的
    //也是调用combineByKey来实现的
    //val createCombiner = (v: V) => {
    //  val hll = new HyperLogLogPlus(p, sp)
    //  hll.offer(v)
    //  hll
    //}
    //val mergeValue = (hll: HyperLogLogPlus, v: V) => {
    //  hll.offer(v)
    //  hll
    //}
    //val mergeCombiner = (h1: HyperLogLogPlus, h2: HyperLogLogPlus) => {
    //  h1.addAll(h2)
    //  h1
    //}
    pairFive.countApproxDistinctByKey(0.1).collect().size

    pairFive.collectAsMap()
    pairFive.lookup(5)

keyBy

val personSeqRDD =
      sc.parallelize(Seq(User("jeffy", 30), User("kkk", 20), User("jeffy", 30), User("kkk", 30)))
    //将RDD变成二元组类型的RDD
    val keyByRDD = personSeqRDD.keyBy(x => x.userId)
    keyByRDD.collect()

groupBy

// 按照user.userId进行分组,也可以多个分组条件
	val groupByRDD = personSeqRDD.groupBy(user => user.userId)
    groupByRDD.glom().collect()

partitioner

mapValuesRDD.partitioner //会记住父亲RDD的分区器

sortByKey

// false 升降序
pairRDD.sortByKey(false).collect()

coalesce

val hdfsFileRDD = sc.textFile("hdfs://master:8020/users/hadoop-jrq/word.txt", 1000)
    hdfsFileRDD.partitions.size // 1000
    //我们通过coalesce来降低分区数量的目的是:
    //分区太多,每个分区的数据量太少,导致太多的task,我们想减少task的数量,所以需要降低分区数
    // 如果分区数太多了,就会造成很多task空跑,浪费资源及效率低,因此需要降低其分区数
    //第一个参数表示我们期望的分区数
    //第二个参数表示是否需要经过shuffle来达到我们的分区数
    val coalesceRDD = hdfsFileRDD.coalesce(100, false)
    coalesceRDD.partitions.size //100

//从1000个分区一下子降到2个分区
    //这里会导致1000个map计算只在2个分区上执行,会导致性能问题
    // 后面的true是map计算后,再重新分区,进行计算
    hdfsFileRDD.map(_ + "test").coalesce(2, true)

wholeTextFiles

// wholeTextFiles 读整个文件夹下的文件,键是文件名,值是内容
    val wholeTextFiles = sc.wholeTextFiles("hdfs://master:8020/users/hadoop-jrq/text/")

binaryFiles

// 类似上面的 key是文件名  值是文件流
    val binaryFilesRDD = sc.binaryFiles("hdfs://master:8020/users/hadoop-jrq/text/")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值