Spark-RDD行动算子

RDD转换方法回顾

Rdd转换算子就是将旧的RDD通过方法转换成一个新的RDD

之所以这样做,就是希望将多个RDD的功能组合在一起(装饰着设计模式)

RDD行动算子介绍

行动算子和转换算子如何区分?

转换算子:将旧的RDD转换成新的RDD,为了组合多个RDD功能

看返回值是否为新的RDD,是则为转换算子。返回值是一个具体的值,则是行动算子

不能看是否触发作业执行来判断

RDD行动算子-Collect

collect方法就是RDD行动算子
RDD的行动算子会触发作业job的执行
collect方法就是将Exector端执行的结果按照分区的顺序拉取(采集)回到Driver端,将结果组合成集合对象

JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3,4),2);
JavaRDD<Object> newRdd = rdd.map(num->num*2);
newRdd.collect().forEach(System.out::println);

如图:如图:要注意不同executor返回的对象顺序不一定 但是内部有顺序
在这里插入图片描述
Spark的计算全部都是在Executor端执行
Spark在编写代码时,调用转换算子,并不会真正的执行,因为只是在Driver端组合功能

JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3,4),2);
//Spark的计算全部都是在Executor端执行的

//Spark在编写代码时,调用转换算子,并不会真正的执行,因为只是在Driver端组合功能
//所以当前代码其实是在Driver端执行
//所以当前的main方法也是driver方法,当前运行main线程,也称之Driver线程
//转换算子中的逻辑代码是在Executor端执行的,并不会在Driver端调用执行
JavaRDD<Object> newRdd = rdd.map(num-> {
    System.out.println("******");
    return num*2;
});
//TODO collect方法就是RDD行动算子
//      RDD的行动算子会触发作业job的执行
//      collect方法就是将Exector端执行的结果按照分区的顺序拉取(采集)回到Driver端,将结果组合成集合对象

newRdd.collect().forEach(System.out::println);

如果不是数字,是HDFS中的文件怎么办?如图会先分片,再去hdfs中拉取文件
在这里插入图片描述
所以collect方法可能会导致多个Executor的大量数据拉取到Driver端,导致内存溢出,所以生产环境慎用

RDD行动算子-其他方法
JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3,4),2);
//TODO 用于采集数据
List<Integer> collect = rdd.collect();
//TODO count获取结果数量
long count = rdd.count();
//TODO first获取结果第一个
Integer first = rdd.first();
//TODO take从结果中获取前N个
List<Integer> take = rdd.take(3);
JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3,4),2);
JavaPairRDD<String, Integer> pairRDD = rdd.mapToPair(
        num -> new Tuple2<>("a", num)
);
//TODO 保存
pairRDD.saveAsTextFile("output1");
pairRDD.saveAsObjectFile("output2");
//单点循环
rdd.collect().forEach(System.out::println);
//分布式循环
//TODO foreach执行效率低  但是占内存比较小
rdd.foreach(
        num-> System.out.println(num)
);
//TODO foreachPartition执行效率高,但是依托于内存大小
rdd.foreachPartition(
        list->{
            System.out.println(list);
        }
);

说明一下Driver端和Excutor端的数据传输的例子
本例子用对象中的数据和被传输到Excutor的数据进行想加,开始时只是普通的对象,没加implements Serializable会报错
在这里插入图片描述
之后在Student对象后面加上implements Serializable,要将Driver端的对象通过网络传递到Executor端,所以这里传输的对象必须要实现可序列化接口,否则无法传递

        JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3,4),2);
        JavaPairRDD<String, Integer> pairRDD = rdd.mapToPair(
                num -> new Tuple2<>("a", num)
        );
        //TODO 对象是在driver执行的
        Student s = new Student();
        //foreach算子是分布式循环:分区内有序,分区间无序
        rdd.foreach(
                num->{
                    //TODO 在Executor端循环遍历的时候使用到Driver端对象
                    //      运行过程中,就需要将Driver端的对象通过网络传递到Executor端,否则无法使用
                    //      这里传输的对象必须要实现可序列化接口,否则无法传递
                    System.out.println(s.age+num);
                }
        );
        jsc.close();
    }
}
class Student implements Serializable {
    public int age=30;
}

在这里插入图片描述

RDD-序列化问题1

当在Executor端用到在Driver的数据,需要拉取数据进行序列化,当发现用到的数据没有序列化时会报错。

以下代码为正确代码:除了RDD方法在Executor端执行,其他都在Driver端,但是rdd.filter用到的q和Search对象没关系,并且String方法可以序列化,所以不会有问题。

public class Spark19_Operate_Action {
    public static void main(String[] args) {
        //TODO 构建spark配置对象
       final SparkConf conf = new SparkConf();
       conf.setMaster("local");
       conf.setAppName("spark");
        //TODO 构建spark的运行环境
        JavaSparkContext jsc = new JavaSparkContext(conf);
        List<String> nums = Arrays.asList("Hadoop", "Hive", "Spark", "Flink");
        JavaRDD<String> rdd = jsc.parallelize(nums,2);

        //RDD算子的逻辑代码实在Excutor端执行的,其他的都是Driver端
        Search search=new Search("H");
        search.match(rdd);
        jsc.close();
    }
}
class Search{
    private String query;
    public Search(String query){
        this.query=query;
    }
    public void match(JavaRDD<String> rdd){
        String q=this.query;
        rdd.filter(
                s->s.startsWith(q)
        ).collect().forEach(System.out::println);
    }
}

如果Search对象为如下这样:就需要对Search对象进行序列化,不然就会报错误。

class Search implements Serializable{
    private String query;
    public Search(String query){
        this.query=query;
    }
    public void match(JavaRDD<String> rdd){
        rdd.filter(
                s->s.startsWith(query)
        ).collect().forEach(System.out::println);
    }
}
RDD-序列化问题2
JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3,4),2);
//foreach算子是分布式循环:分区内有序,分区间无序
rdd.foreach(
        num->System.out.println(num)
);
//Jdk1.8的函数式编程其实采用的是对象模拟出来的
rdd.foreach(System.out::println);//会报错,出现没有序列化问题,所以不能用函数式编程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值