sgg大数据-spark-02---一天十个---20210327

RDD的作用。

从以上流程可以看出 RDD 在整个流程中主要用于将逻辑进行封装,并生成 Task 发送给
Executor 节点执行计算,接下来我们就一起看看 Spark 框架中 RDD 是具体是如何进行数据
处理的。

---31---

用的比较多的是在内存中创建和文件中创建。

在集合中创建RDD

seq和set的区别:https://blog.csdn.net/qq_36932624/article/details/83060446

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Memory {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        // *表示当前系统的最大可用核数 不写就是单线程
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD
        // 从内存中创建RDD,将内存中集合的数据作为处理的数据源
        val seq = Seq[Int](1,2,3,4)

        // parallelize : 并行
        //val rdd: RDD[Int] = sc.parallelize(seq)
        // makeRDD方法在底层实现时其实就是调用了rdd对象的parallelize方法。
        val rdd: RDD[Int] = sc.makeRDD(seq)

        rdd.collect().foreach(println)

        // TODO 关闭环境
        sc.stop()
    }
}

local的*表示的什么呢,表示的是当前本机的核心数。

---32---

默认是以当前目录的根路径为基准的。

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_File {
    def main(args: Array[String]): Unit = {
        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)
        // TODO 创建RDD
        // 从文件中创建RDD,将文件中的数据作为处理的数据源
        // path路径默认以当前环境的根路径为基准。可以写绝对路径,也可以写相对路径
        //sc.textFile("D:\\mineworkspace\\idea\\classes\\atguigu-classes\\datas\\1.txt")
        // 相对路径是当前的项目的根
        //val rdd: RDD[String] = sc.textFile("datas/1.txt")
        // path路径可以是文件的具体路径,也可以目录名称
        //val rdd = sc.textFile("datas")
        // path路径还可以使用通配符 *
        //val rdd = sc.textFile("datas/1*.txt")
        // path还可以是分布式存储系统路径:HDFS
        val rdd = sc.textFile("hdfs://linux1:8020/test.txt")
        rdd.collect().foreach(println)
        // TODO 关闭环境
        sc.stop()
    }
}

---33---

以文件为单位读取数据:

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_File1 {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD
        // 从文件中创建RDD,将文件中的数据作为处理的数据源

        // textFile : 以行为单位来读取数据,读取的数据都是字符串
        // wholeTextFiles : 以文件为单位读取数据
        //    读取的结果表示为元组,第一个元素表示文件路径,第二个元素表示文件内容
        val rdd = sc.wholeTextFiles("datas")

        rdd.collect().foreach(println)

        // TODO 关闭环境
        sc.stop()
    }
}

读取内容的样子:

(file:/G:/CODE_MY/sggBigData/atguigu-classes/datas/1.txt,hello word
hello spark)
(file:/G:/CODE_MY/sggBigData/atguigu-classes/datas/2.txt,hello word1
hello spark1)

---34---

关于并行度:

几个分区几个task,发给executor。

z

不传的话就是按照核心数分区的。

还是可以配置的:

代码:

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Memory_Par {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        sparkConf.set("spark.default.parallelism", "5")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD
        // RDD的并行度 & 分区
        // makeRDD方法可以传递第二个参数,这个参数表示分区的数量
        // 第二个参数可以不传递的,那么makeRDD方法会使用默认值 : defaultParallelism(默认并行度)
        //     scheduler.conf.getInt("spark.default.parallelism", totalCores)
        //    spark在默认情况下,从配置对象中获取配置参数:spark.default.parallelism
        //    如果获取不到,那么使用totalCores属性,这个属性取值为当前运行环境的最大可用核数
        //val rdd = sc.makeRDD(List(1,2,3,4),2)
        val rdd = sc.makeRDD(List(1,2,3,4))

        // 将处理的数据保存成分区文件
        rdd.saveAsTextFile("output")

        // TODO 关闭环境
        sc.stop()
    }
}

--------------------------------

并行就是分区。

 

并行就是分区。

分区之间是独立的,有独立的task。task发给executor。

一个executor三个task发过去只能有一个执行。

默认的并行度,不传的话就是cpu的核心数量。

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Memory_Par {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        sparkConf.set("spark.default.parallelism", "2")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD
        // RDD的并行度 & 分区
        // makeRDD方法可以传递第二个参数,这个参数表示分区的数量
        // 第二个参数可以不传递的,那么makeRDD方法会使用默认值 : defaultParallelism(默认并行度)
        //     scheduler.conf.getInt("spark.default.parallelism", totalCores)
        //    spark在默认情况下,从配置对象中获取配置参数:spark.default.parallelism
        //    如果获取不到,那么使用totalCores属性,这个属性取值为当前运行环境的最大可用核数
        //val rdd = sc.makeRDD(List(1,2,3,4),2)
        val rdd = sc.makeRDD(List(1,2,3,4))

        // 将处理的数据保存成分区文件
        rdd.saveAsTextFile("output")

        // TODO 关闭环境
        sc.stop()
    }
}

---35---

数据不多但是分区比较多该怎么办呢,数据是如何放在分区里面的呢?

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Memory_Par1 {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD

        // 【1,2】,【3,4】
        //val rdd = sc.makeRDD(List(1,2,3,4), 2)
        // 【1】,【2】,【3,4】 不均匀的话是怎么存放的呢?
        //val rdd = sc.makeRDD(List(1,2,3,4), 3)
        // 【1】,【2,3】,【4,5】
        val rdd = sc.makeRDD(List(1,2,3,4,5), 3)

        // 将处理的数据保存成分区文件
        rdd.saveAsTextFile("output")

        // TODO 关闭环境
        sc.stop()
    }
}

分区的规律是什么呢?

看下slice切分的思想,数据是12345,分区是3:

接下来的功能:

这个是源码 就是这个规律。

1 2 3 4 5  3

0=>(0,1)  1

1=>(1,3)  2 3

2=>(3,5) 4 5

注意一点,这个效果是一样的: sparkConf.set("spark.default.parallelism", "2")

---36---

在文件中读取数据是如何分区的呢?

我们点进去源码:

点进去:

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_File_Par {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD
        // textFile可以将文件作为数据处理的数据源,默认也可以设定分区。
        //     minPartitions : 最小分区数量
        //     math.min(defaultParallelism, 2)
        //val rdd = sc.textFile("datas/1.txt")
        // 如果不想使用默认的分区数量,可以通过第二个参数指定分区数
        // Spark读取文件,底层其实使用的就是Hadoop的读取方式
        // 分区数量的计算方式:
        //    totalSize = 7
        //    goalSize =  7 / 2 = 3(byte)

        //    7 / 3 = 2...1 (1.1) + 1 = 3(分区)

        //
        val rdd = sc.textFile("datas/1.txt", 2)

        rdd.saveAsTextFile("output")


        // TODO 关闭环境
        sc.stop()
    }
}

真正的分区可能比最小分区的值要大。

分区数量是怎么算出来的呢?

所有的读取的文件统计字节数:

字节数是7.

7/2=3,表示每个分区存放三个字节。

7/3=2...1:2个分区+1,1/3>0.1则产生新的分区,剩余的数占分区的字节数的多少。

3个分区。

---37---

文件读取的话,数据是如何存储的呢?

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_File_Par1 {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD
        // TODO 数据分区的分配
        // 1. 数据以行为单位进行读取
        //    spark读取文件,采用的是hadoop的方式读取,所以一行一行读取,和字节数没有关系
        // 2. 数据读取时以偏移量为单位,偏移量不会被重复读取
        /*
           1@@   => 012
           2@@   => 345
           3     => 6

         */
        // 3. 数据分区的偏移量范围的计算
        // 0 => [0, 3]  => 12
        // 1 => [3, 6]  => 3
        // 2 => [6, 7]  =>

        // 【1,2】,【3】,【】
        val rdd = sc.textFile("datas/1.txt", 2)

        rdd.saveAsTextFile("output")


        // TODO 关闭环境
        sc.stop()
    }
}

读取是一行一行读取的。

这个文件里面是123

---38---

这个文件里面是

1234567

89

0

代码:

package com.atguigu.bigdata.spark.core.rdd.builder

import org.apache.spark.{SparkConf, SparkContext}

object Spark03_RDD_File_Par2 {

    def main(args: Array[String]): Unit = {

        // TODO 准备环境
        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
        val sc = new SparkContext(sparkConf)

        // TODO 创建RDD

        // 14byte / 2 = 7byte
        // 14 / 7 = 2(分区)

        /*
        1234567@@  => 012345678
        89@@       => 9101112
        0          => 13

        [0, 7]   => 1234567
        [7, 14]  => 890

         */

        // 如果数据源为多个文件,那么计算分区时以文件为单位进行分区
        val rdd = sc.textFile("datas/word.txt", 2)

        rdd.saveAsTextFile("output")


        // TODO 关闭环境
        sc.stop()
    }
}

---39---

RDD的方法。

1.转换,就是旧的RDD转换为新的RDD,就是flatmap和map等。

2.行动:触发作业的执行,collect。

RDD的算子分为两种:转换和行动算子

---40---

map算子:

都可以的:

代码:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - map

        val rdd = sc.makeRDD(List(1,2,3,4))
        // 1,2,3,4
        // 2,4,6,8

        // 转换函数 在函数里面得方法就是函数
        def mapFunction(num:Int): Int = {
            num * 2
        }

        var fun = (i:Int)=>i*2;

        val mapRDD: RDD[Int] = rdd.map(fun)
        //val mapRDD: RDD[Int] = rdd.map((num:Int)=>{num*2})
        //val mapRDD: RDD[Int] = rdd.map((num:Int)=>num*2)
        //val mapRDD: RDD[Int] = rdd.map((num)=>num*2)
        //val mapRDD: RDD[Int] = rdd.map(num=>num*2)
//        val mapRDD: RDD[Int] = rdd.map(_*2)

        mapRDD.collect().foreach(println)

        sc.stop()

    }
}

---41---

我们解析服务器的日志信息:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Operator_Transform_Test {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - map
        val rdd = sc.textFile("datas1/apache.log")

        // 长的字符串
        // 短的字符串
        val mapRDD: RDD[String] = rdd.map(
            line => {
                val datas = line.split(" ")
                datas(6)
            }
        )
        mapRDD.collect().foreach(println)

        sc.stop()

    }
}

---42---

如何体现rdd方法的并行计算:

代码:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Operator_Transform_Par {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - map

        // 1. rdd的计算一个分区内的数据是一个一个执行逻辑
        //    只有前面一个数据全部的逻辑执行完毕后,才会执行下一个数据。
        //    分区内数据的执行是有序的。
        // 2. 不同分区数据计算是无序的。
        val rdd = sc.makeRDD(List(1,2,3,4),2)

        val mapRDD = rdd.map(
            num => {
                println(">>>>>>>> " + num)
                num
            }
        )
        val mapRDD1 = mapRDD.map(
            num => {
                println("######" + num)
                num
            }
        )

        mapRDD1.collect()

        sc.stop()

    }
}

按照老师的演示:

我们看下这个其实是乱的。

我们改为一个分区:

RDD一个分区内的数据是一个一个执行的逻辑的,前面逻辑执行完才会执行下一个,分区内的数据是有序的,不同分区的数据是无序的。

两个分区的数据一定是这样的。一个分区是先走1 再走2的,1和3谁先执行是不一定的。

 

---43---

单个分区是串行的,效率很低的,我们用缓冲区一个分区的数据全部拿到了之后再做操作可以。

spark算子的缓冲区操作:

这个内存小数据量大的话可能会有问题,会将分区加载到内存,存在引用的话是不会释放的额。

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - mapPartitions
        val rdd = sc.makeRDD(List(1,2,3,4), 2)

        // mapPartitions : 可以以分区为单位进行数据转换操作
        //                 但是会将整个分区的数据加载到内存进行引用
        //                 如果处理完的数据是不会被释放掉,存在对象的引用。
        //                 在内存较小,数据量较大的场合下,容易出现内存溢出。
        val mpRDD: RDD[Int] = rdd.mapPartitions(
            iter => {
                // 有多少个分区这个箭头执行都多少次
                println(">>>>>>>>>>")
                iter.map(_ * 2)
            }
        )
        mpRDD.collect().foreach(println)

        sc.stop()

    }
}

分析结果:有多少个分区箭头执行多少次的

---44---

小功能,获取每个分区的最大值:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_Operator_Transform_Test {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - mapPartitions-
        val rdd = sc.makeRDD(List(1,2,3,4), 2)

        // 【1,2】,【3,4】
        // 【2】,【4】
        val mpRDD = rdd.mapPartitions(
            iter => {
                List(iter.max).iterator
            }
        )
        mpRDD.collect().foreach(println)

        sc.stop()

    }
}

---45---

map和MapPartition

---46---

分区之间是无序的。

分区索引。

如何看下数据在哪个分区里面?

---47---

扁平映射:

---48---

再次做一个小功能,还是扁平化操作,3不是一个集合,如何把3拆分开呢:

---49---

作用是什么?

需求:分区取最大值,两个分区最大值求和

---50---

理解分区的不变的含义:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark01_RDD_Operator_Transform_Part {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - map
        val rdd = sc.makeRDD(List(1,2,3,4),2)
        // 【1,2】,【3,4】
        rdd.saveAsTextFile("output")
        val mapRDD = rdd.map(_*2)
        // 【2,4】,【6,8】
        mapRDD.saveAsTextFile("output1")

        sc.stop()

    }
}

---51---

groupby:
 

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark06_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - groupBy
        val rdd : RDD[Int] = sc.makeRDD(List(1,2,3,4), 2)

        // groupBy会将数据源中的每一个数据进行分组判断,根据返回的分组key进行分组
        // 相同的key值的数据会放置在一个组中
        def groupFunction(num:Int) = {
            num % 2
        }

        val groupRDD: RDD[(Int, Iterable[Int])] = rdd.groupBy(groupFunction)

        groupRDD.collect().foreach(println)


        sc.stop()

    }
}

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark06_RDD_Operator_Transform1 {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - groupBy
        val rdd  = sc.makeRDD(List("Hello", "Spark", "Scala", "Hadoop"), 2)

        // 分组和分区没有必然的关系
        val groupRDD = rdd.groupBy(_.charAt(0))

        groupRDD.collect().foreach(println)


        sc.stop()

    }
}

---52---

分组和分区是没有必然的联系的。

shuffle来袭,数据被打乱了。

---53---

获取每个时间段的访问量:

  

时间段的访问量:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import java.text.SimpleDateFormat
import java.util.Date

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark06_RDD_Operator_Transform_Test {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - groupBy
        val rdd = sc.textFile("datas1/apache.log")
        // groupBy返回的是一个迭代器
        val timeRDD: RDD[(String, Iterable[(String, Int)])] = rdd.map(
            line => {
                val datas = line.split(" ")
                // 数组取第几位
                val time = datas(3)
                //time.substring(0, )
                val sdf = new SimpleDateFormat("dd/MM/yyyy:HH:mm:ss")
                val date: Date = sdf.parse(time)
                val sdf1 = new SimpleDateFormat("HH")
                val hour: String = sdf1.format(date)
                (hour, 1)
            }
        ).groupBy(_._1)
        timeRDD.map{
            case ( hour, iter ) => {
                (hour, iter.size)
            }
        }.collect.foreach(println)


        sc.stop()

    }
}

---54---

filter:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import java.text.SimpleDateFormat
import java.util.Date

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark07_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - filter
        val rdd = sc.makeRDD(List(1,2,3,4))

        val filterRDD: RDD[Int] = rdd.filter(num=>num%2!=0)

        filterRDD.collect().foreach(println)


        sc.stop()

    }
}

注意一点:

将数据根据指定的规则进行筛选过滤,符合规则的数据保留,不符合规则的数据丢弃。
当数据进行筛选过滤后,分区不变,但是分区内的数据可能不均衡,生产环境下,可能会出
现数据倾斜。

小功能,过滤出来特定日期的数据

cpackage com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark07_RDD_Operator_Transform_Test {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - filter
        val rdd = sc.textFile("datas/apache.log")

        rdd.filter(
            line => {
                val datas = line.split(" ")
                val time = datas(3)
                time.startsWith("17/05/2015")
            }
        ).collect().foreach(println)


        sc.stop()

    }
}

---55---

sample:抽取样本的数据

代码:

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.{SparkConf, SparkContext}

object Spark08_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - filter
        val rdd = sc.makeRDD(List(1,2,3,4,5,6,7,8,9,10))

        // sample算子需要传递三个参数
        // 1. 第一个参数表示,抽取数据后是否将数据返回 true(放回),false(丢弃)
        // 2. 第二个参数表示,
        //         如果抽取不放回的场合:数据源中每条数据被抽取的概率,基准值的概念
        //         如果抽取放回的场合:表示数据源中的每条数据被抽取的可能次数
        // 3. 第三个参数表示,抽取数据时随机算法的种子
        //                    如果不传递第三个参数,那么使用的是当前系统时间
        println(rdd.sample(
            false,
            0.4
//            1
        ).collect().mkString(","))

//        println(rdd.sample(
//            true,
//            2
//            //1
//        ).collect().mkString(","))


        sc.stop()

    }
}

第一种情况:

   println(rdd.sample(
            false,
            0.4,
            1

返回值:种子确定好每个数据的额概率就被确定好了,每次的值是相同的。

第二种情况:数据每次是不一样的

    println(rdd.sample(
            false,
            0.4
//            1
        ).collect().mkString(","))

第三种情况:抽取完的数据是要放回去的

2指的是抽取的次数可能是2次。

 println(rdd.sample(
            true,
            2
            //1
        ).collect().mkString(","))

我们在数据的倾斜可能会使用的。

---56---

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark09_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - filter
        val rdd = sc.makeRDD(List(1,2,3,4,1,2,3,4))

        // map(x => (x, null)).reduceByKey((x, _) => x, numPartitions).map(_._1)

        // (1, null),(2, null),(3, null),(4, null),(1, null),(2, null),(3, null),(4, null)
        // (1, null)(1, null)(1, null)
        // (null, null) => null
        // (1, null) => 1
        val rdd1: RDD[Int] = rdd.distinct()

        rdd1.collect().foreach(println)



        sc.stop()

    }
}

这个讲了原理,暂时不看了。

---57---

缩减分区:

分区是并行计算的,两个分区就要有两个Exccutor取计算,浪费计算资源的。

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark10_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - filter
        val rdd = sc.makeRDD(List(1,2,3,4,5,6), 3)

        // coalesce方法默认情况下不会将分区的数据打乱重新组合
        // 这种情况下的缩减分区可能会导致数据不均衡,出现数据倾斜
        // 如果想要让数据均衡,可以进行shuffle处理
        //val newRDD: RDD[Int] = rdd.coalesce(2)
        val newRDD: RDD[Int] = rdd.coalesce(2,true)

        newRDD.saveAsTextFile("output")




        sc.stop()

    }
}

默认是不会打乱重新组合的,会缩减分区,就会造成数据的倾斜。

想让数据均衡就要shuffle:

---58---

如何扩大分区呢?

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark11_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - filter
        val rdd = sc.makeRDD(List(1,2,3,4,5,6), 2)

        // coalesce算子可以扩大分区的,但是如果不进行shuffle操作,是没有意义,不起作用。
        // 所以如果想要实现扩大分区的效果,需要使用shuffle操作
        // spark提供了一个简化的操作
        // 缩减分区:coalesce,如果想要数据均衡,可以采用shuffle
        // 扩大分区:repartition, 底层代码调用的就是coalesce,而且肯定采用shuffle
        //val newRDD: RDD[Int] = rdd.coalesce(3, true)
        val newRDD: RDD[Int] = rdd.repartition(3)

        newRDD.saveAsTextFile("output")




        sc.stop()

    }
}

也会分为shuffle和shffle。没有事没有意义的,扩大分区一定要shuffle。

---59---

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark12_RDD_Operator_Transform {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - sortBy
        val rdd = sc.makeRDD(List(6,2,4,5,3,1), 2)

        val newRDD: RDD[Int] = rdd.sortBy(num=>num)

        newRDD.saveAsTextFile("output")




        sc.stop()

    }
}

按照分区排序的。

package com.atguigu.bigdata.spark.core.rdd.operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark12_RDD_Operator_Transform1 {

    def main(args: Array[String]): Unit = {

        val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
        val sc = new SparkContext(sparkConf)

        // TODO 算子 - sortBy
        val rdd = sc.makeRDD(List(("1", 1), ("11", 2), ("2", 3)), 2)

        // sortBy方法可以根据指定的规则对数据源中的数据进行排序,默认为升序,第二个参数可以改变排序的方式
        // sortBy默认情况下,不会改变分区。但是中间存在shuffle操作
        val newRDD = rdd.sortBy(t=>t._1.toInt, false)

        newRDD.collect().foreach(println)




        sc.stop()

    }
}

---60---

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值