Spark_Spark中 map, mapPartition, flatMap, flatMapToPair 方法简介,区别 与示例

调研背景 :

本博主刚接触spark 开发,对其中的API 并不是特别的熟悉,对于以上提到的4种API 常分不清用法,故写下这篇文章作为参考。

如果有别的见解,希望踊跃留言 ~~~


主要的测试场景,模仿对语句中的单词进行切分~。(按照空格进行单词切分,词频统计的前一个步奏。 


maven依赖:

<dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>2.2.0</version>
        </dependency>


方法介绍

Map :(不推荐使用)

    map函数会对每一条输入进行指定的操作,然后为每一条输入返回一个对象。

示例代码:

JavaRDD<String[]> mapResult = linesRDD.map(new Function<String, String[]>() {

            @Override
            public String[] call(String s) throws Exception {
                return s.split(" ");
            }
        });


MapPartition :

  MapPartition  函数会对每个分区中的一组数据进行相应的操作,并最终返回一个指定对象的迭代器。

建议使用 MapPartition 取代  Map 函数:

原因如下:

优点1:

对于 一些初始化操作,如果用map 函数可能需要对每一条数据都进行一次调用,而使用  MapPartition  可以一个分区只调用一次初始化操作,资源使用更高效!!

优点2:

通过mapPartition 可以非常方便的对返回结果进行过滤 (比如错误数据过滤),map 较难实现。

MapPartition 也可以完成 FlatMap 相类似的功能;(但是底部的实现原理可能并不相同),见后文

示例代码:

 JavaRDD<String[]> mapPartitionsResult = linesRDD.mapPartitions(new FlatMapFunction<Iterator<String>, String[]>() {

            @Override
            public Iterator<String[]> call(Iterator<String> stringIterator) throws Exception {

                List<String[]> resultArr = new ArrayList<>();
                while (stringIterator.hasNext()) {
                    String line = stringIterator.next();
                    String[] tmpResult = line.split(" ");
                    resultArr.add(tmpResult);
                }
                return resultArr.iterator();
            }
        });


FlatMap:

   flatMap函数则是两个操作的集合——正是“先映射后扁平化”:

操作1:同map函数一样:对每一条输入进行指定的操作,然后为每一条输入返回一个对象

操作2:最后将所有对象合并为一个对象

  FlatMap 与 Map 的主要区别 :

Map 主要转换是一条数据 返回 一条数据

FlatMap 将一条数据转换为 一组数据 (迭代器),主要用于将一条记录转换为多条记录的场景,如对 每行文章中的单词进行切分,

返回 每行中所有单词。

示例代码:

JavaRDD<String> flatMapResult = linesRDD.flatMap(new FlatMapFunction<String, String>() {

            @Override
            public Iterator<String> call(String s) throws Exception {
                return Arrays.asList(s.split(" ")).iterator();
            }
        });

其实:按照我的理解, MapPartition 也可以完成 FlatMap 相类似的功能;(但是底部的实现原理可能并不相同)

假设实现的功能是将语句按照 “ ”(空格)进行切分, 返回单词列表:


System.out.println("MapPartition simulate flatMap operation");
        JavaRDD<String> mapPartitionLikeFlatMapResult = linesRDD.mapPartitions(
                new FlatMapFunction<Iterator<String>, String>() {
                    @Override
                    public Iterator<String> call(Iterator<String> stringIterator) throws Exception {
                        List<String> resultList = new ArrayList<>();
                        while(stringIterator.hasNext()){
                            String tmpLine = stringIterator.next();
                            String[] tmpWords = tmpLine.split(" ");
                            for(String tmpString : tmpWords){
                                resultList.add(tmpString);
                            }
                        }
                        return resultList.iterator();
                    }
                }
        );
        mapPartitionLikeFlatMapResult.foreach(new VoidFunction<String>() {

            @Override
            public void call(String s) throws Exception {
                System.out.println(s);
            }
        });
        System.out.println("\n\n");


FlatMapToPair:

   flatMapToPair  其实是在FlatMap 函数基础上将返回的数据转换为了 1个Tuple, 即 key-value 格式的数据。方便相同的key 的数据进行后续的统计如统计次数等操作。

示例代码:

JavaPairRDD<String, Integer> flatMapToPairResult = linesRDD.flatMapToPair(

                new PairFlatMapFunction<String, String, Integer>() {
                    @Override
                    public Iterator<Tuple2<String, Integer>> call(String s) throws Exception {

                        List<Tuple2<String, Integer>> resultTuple = new ArrayList<>();
                        String[] tmpList = s.split(" ");
                        for (String tmpString : tmpList) {
                            resultTuple.add(new Tuple2<>(tmpString, 1));
                        }
                        return resultTuple.iterator();
                    }
                });


整体的示例代码:

package com.spark.test.batch.job;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.PairFlatMapFunction;
import org.apache.spark.api.java.function.VoidFunction;
import scala.Tuple2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * Created by szh on 2018/5/2.
 *
 * @author szh
 * @date 2018/5/2
 */
public class MultiMapCompare {

    public static void main(String[] args) {

        SparkConf sparkConf = new SparkConf();
        sparkConf.setAppName("MultiMapCompare").setMaster("local[2]");
        JavaSparkContext sparkContext = new JavaSparkContext(sparkConf);
        sparkContext.setLogLevel("ERROR");

        List<String> linesList = new ArrayList<>();
        linesList.add("You are a bad man");
        linesList.add("Just a test job");
        JavaRDD<String> linesRDD = sparkContext.parallelize(linesList);


        System.out.println("map Result");
        JavaRDD<String[]> mapResult = linesRDD.map(new Function<String, String[]>() {

            @Override
            public String[] call(String s) throws Exception {
                return s.split(" ");
            }
        });
        mapResult.foreach(new VoidFunction<String[]>() {

            @Override
            public void call(String[] strings) throws Exception {
                for (String tmp : strings) {
                    System.out.println(tmp);
                }
            }
        });
        System.out.println("\n\n");


        System.out.println("mapPartitions Result");
        JavaRDD<String[]> mapPartitionsResult = linesRDD.mapPartitions(new FlatMapFunction<Iterator<String>, String[]>() {

            @Override
            public Iterator<String[]> call(Iterator<String> stringIterator) throws Exception {

                List<String[]> resultArr = new ArrayList<>();
                while (stringIterator.hasNext()) {
                    String line = stringIterator.next();
                    String[] tmpResult = line.split(" ");
                    resultArr.add(tmpResult);
                }
                return resultArr.iterator();
            }
        });
        mapPartitionsResult.foreach(new VoidFunction<String[]>() {
            @Override
            public void call(String[] strings) throws Exception {
                for (String tmp : strings) {
                    System.out.println(tmp);
                }
            }
        });
        System.out.println("\n\n");


        System.out.println("flatMap Result");
        JavaRDD<String> flatMapResult = linesRDD.flatMap(new FlatMapFunction<String, String>() {

            @Override
            public Iterator<String> call(String s) throws Exception {
                return Arrays.asList(s.split(" ")).iterator();
            }
        });
        flatMapResult.foreach(new VoidFunction<String>() {

            @Override
            public void call(String s) throws Exception {
                System.out.println(s);
            }
        });
        System.out.println("\n\n");


        System.out.println("flatMapToPair Result");
        JavaPairRDD<String, Integer> flatMapToPairResult = linesRDD.flatMapToPair(

                new PairFlatMapFunction<String, String, Integer>() {
                    @Override
                    public Iterator<Tuple2<String, Integer>> call(String s) throws Exception {

                        List<Tuple2<String, Integer>> resultTuple = new ArrayList<>();
                        String[] tmpList = s.split(" ");
                        for (String tmpString : tmpList) {
                            resultTuple.add(new Tuple2<>(tmpString, 1));
                        }
                        return resultTuple.iterator();
                    }
                });
        flatMapToPairResult.foreach(new VoidFunction<Tuple2<String, Integer>>() {
            @Override
            public void call(Tuple2<String, Integer> stringIntegerTuple2) throws Exception {
                System.out.println(stringIntegerTuple2);
            }
        });
        System.out.println("\n\n");

        sparkContext.close();
    }

}

========

运行结果:

map Result
You
are
a
bad
man
Just
a
test
job



mapPartitions Result
Just
a
test
job
You
are
a
bad
man



flatMap Result
Just
a
test
job
You
are
a
bad
man



flatMapToPair Result
(Just,1)
(a,1)
(test,1)
(job,1)
(You,1)
(are,1)
(a,1)
(bad,1)
(man,1)






  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark的`map`和`flatMap`是两种常用的转换操作,它们的底层原理有所不同。 `map`算子的底层原理如下: 1. 当调用`map`算子时,Spark会将这个操作添加到RDD的转换操作序列,并记录下这个转换操作。 2. 当遇到一个Action算子时,Spark会根据RDD的依赖关系和转换操作序列,构建一个执行计划(DAG)。 3. 在执行计划Spark会将每个分区的数据通过转换函数进行映射,生成一个新的RDD。这个映射函数可以是用户自定义的函数,也可以是Lambda表达式。 4. 最后,Spark将生成的新RDD返回给驱动器程序或写入外部存储系统。 而`flatMap`算子的底层原理与`map`有些不同: 1. `flatMap`算子首先会对每个输入元素应用一个函数,这个函数的返回值可以是多个元素组成的序列。 2. 然后,`flatMap`算子会将所有生成的元素展平成一个新的RDD。 3. 具体地说,`flatMap`算子会将每个输入元素与其生成的元素一起组合,并形成一个新的RDD。 这里是一个示例代码,展示了`map`和`flatMap`算子的使用和底层原理: ```python # 创建一个包含字符串的RDD rdd = sc.parallelize(["Hello world", "Spark is great"]) # 使用map算子对每个字符串进行单词拆分 mapped_rdd = rdd.map(lambda x: x.split(" ")) # 使用flatMap算子对每个字符串进行单词拆分,并展平成一个新的RDD flattened_rdd = rdd.flatMap(lambda x: x.split(" ")) # 输出map算子的结果 print(mapped_rdd.collect()) # 输出: [['Hello', 'world'], ['Spark', 'is', 'great']] # 输出flatMap算子的结果 print(flattened_rdd.collect()) # 输出: ['Hello', 'world', 'Spark', 'is', 'great'] ``` 在上面的示例,我们首先创建了一个包含字符串的RDD,然后使用`map`算子和`flatMap`算子对每个字符串进行单词拆分。`map`算子生成了一个包含列表的RDD,而`flatMap`算子生成了一个展平后的RDD。最后,我们分别打印了这两个RDD的结果。 总结起来,`map`算子和`flatMap`算子在底层的实现上有一些差别,主要体现在对元素的处理方式和生成新RDD的方式上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值