“戏”说Spark-Spark核心-RDD转换操作算子详解(一)

“戏”说Spark-Spark核心-RDD转换行动类算子详解
算子概述
对于RDD可以有两种计算方式:
转换(返回值还是一个RDD)---懒执行
操作(返回值不是一个RDD)---立即执行
转换(Transformations) (如:map, filter, groupBy, join等),Transformations操作是Lazy的,也就是说从一个RDD转换生成另一个RDD的操作不是马上执行,Spark在遇到Transformations操作时只会记录需要这样的操作,并不会去执行,需要等到有Actions操作的时候才会真正启动计算过程进行计算。
操作(Actions) (如:count, collect, save等),Actions操作会返回结果或把RDD数据写到存储系统中。Actions是触发Spark启动计算的动因。
我们可以形象的使用下图表示Spark的输入、运行转换、输出。

  Spark的输入、运行转换、输出。在运行转换中通过算子对RDD进行转换。算子是RDD中定义的函数,可以对RDD中的数据进行转换和操作。
      ·输入:在Spark程序运行中,数据从外部数据空间(例如,HDFS、Scala集合或数据)输入到Spark,数据就进入了Spark运行时数据空间,会转化为Spark中的数据块,通过BlockManager进行管理。
      ·运行:在Spark数据输入形成RDD后,便可以通过变换算子fliter等,对数据操作并将RDD转化为新的RDD,通过行动(Action)算子,触发Spark提交作业。如果数据需要复用,可以通过Cache算子,将数据缓存到内存。
      ·输出:程序运行结束数据会输出Spark运行时空间,存储到分布式存储中(如saveAsTextFile输出到HDFS)或Scala数据或集合中( collect输出到Scala集合,count返回Scala Int型数据)。
  Spark的核心数据模型是RDD,但RDD是个抽象类,具体由各子类实现,如MappedRDD、ShuffledRDD等子类。Spark将常用的大数据操作都转化成为RDD的子类。
常用算子总结:
官方文档中常用算子:

翻译:
Action算子:

Transformations算子:

如何区分Transformations算子和Action类算子?
常用的Transformations算子+Action算子案例演示:代码可直接运行

package spark.mySpark.transformationAndaction;
import groovy.lang.Tuple;
import java.util.Arrays;
import java.util.List;
import org.apache.hadoop.hive.ql.parse.HiveParser_IdentifiersParser.sysFuncNames_return;
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.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
//java中的元组使用scala中的Tuple
import scala.Tuple2;
/**
* @author
* Spark算子演示:
* Transformation类算子
* map
* flatMap
* filter
* sortByKey
* reduceByKey
* sample
* Action类算子:
* count
* collect
* foreach
*/
public class transformation_test {
@SuppressWarnings("resource")
public static void main(String[] args) {
//因为java是面向对象的语言,当使用java来写Spark代码的时候,是传递对象,自动的提示生成返回值可以简化开发
//快捷键:Ctrl+1
//Spark应用程序的配置文件对象,可以设置:1:运行模式,2:应用程序Application的名称,3:运行时的资源的需求
SparkConf sparkConf = new SparkConf().setAppName("transformation_test").setMaster("local[3]");
//SparkContext是非常的重要的,它是通往集群的唯一的通道
JavaSparkContext sparkContext = new JavaSparkContext(sparkConf);
//加载文件生成RDD
JavaRDD<String> textFileRDD= sparkContext.textFile("words.txt");
//==========================filter(function(T,Boolean))=========================//
//filter算子是Transformation类算子,返回一个由通过filter()的函数的元素组成的RDD,结果为true的元素会返回,可以用于过滤
//第一个泛型是textFileRDD里内容的类型,Boolean是返回值类型
JavaRDD<String> filterRDD = textFileRDD.filter(new Function<String, Boolean>() {
/**
* 分布式的程序:对象需要走网络传输
* 添加序列化id
*/
private static final long serialVersionUID = 1L;
public Boolean call(String line) throws Exception {
//过滤掉java
System.out.println("是否执行filter算子");
return !line.contains("java");
}
});
//============================foreach========================================//
//foreach算子是Action类算子,遍历RDD的计算结果
filterRDD.foreach(new VoidFunction<String>() {
private static final long serialVersionUID = 1L;
public void call(String word) throws Exception {
System.out.println(word);
}
});
//================================collect=========================//
//collect算子是Action类算子:将在集群中运行任务的结果拉回Driver端
//注意:当计算结果很大的时候,会导致Driver端OOM
List<String> list = filterRDD.collect();
for(String string:list){
System.out.println(string);
}
//===============================================map=========================//
//map算子是transformation类算子,一般用于改变RDD的内数据的内容格式
//String输入数据的类型,第二个为返回值类型
JavaRDD<Integer> mapRDD = textFileRDD.map(new Function<String, Integer>() {
private static final long serialVersionUID = 1L;
public Integer call(String line) throws Exception {
return line.contains("java")?1:0;
}
});
mapRDD.foreach(new VoidFunction<Integer>() {
private static final long serialVersionUID = 1L;
public void call(Integer num) throws Exception {
System.out.println(num);
}
});
//============================================sample=========================//
//sample算子是一个Transformation类算子,通常用于大数据中的抽样
//withReplacement:是否为放回式的抽样,false为不放会式抽样。fraction为抽样的比例,seed为随机种子:随机抽样算法的初始值
JavaRDD<String> sampleRDD = textFileRDD.sample(true, 0.5);
long count= sampleRDD.count();
System.out.println(count);
//=========================================flatmap=========================//
//flatmap:map+flat,input 1 output *
//map :input 1 output 1
//切分单词
JavaRDD<String> flatMapRDD = textFileRDD.flatMap(new FlatMapFunction<String, String>() {
private static final long serialVersionUID = 1L;
//返回迭代器
public Iterable<String> call(String line) throws Exception {
return Arrays.asList(line.split(" "));
}
});
List<String> collect = flatMapRDD.collect();
for(String string:collect){
System.out.println("word="+string);
}
//===============================sortByKey=========================//
//在java的API中:将RDD转化为(K,V)格式的RDD,需要使用**toPair
//第一个为输入数据的类型,第二个,第三个参数为返回的K,V
List<Tuple2<String,Integer>> temp = flatMapRDD.mapToPair(new PairFunction<String, String, Integer>() {
private static final long serialVersionUID = 1L;
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
// reduceByKey为Transformation类算子
}).reduceByKey(new Function2<Integer, Integer, Integer>() {
private static final long serialVersionUID = 1L;
public Integer call(Integer v1, Integer v2) throws Exception {
//循环反复将v1+v2的值累加
return v1+v2;
}
//变换(K,V)格式的RDD
}).mapToPair(new PairFunction<Tuple2<String,Integer>, Integer, String>() {
private static final long serialVersionUID = 1L;
public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple)
throws Exception {
return new Tuple2<Integer, String>(tuple._2, tuple._1);
}
}).sortByKey(false).mapToPair(new PairFunction<Tuple2<Integer,String>, String, Integer>() {
private static final long serialVersionUID = 1L;
public Tuple2<String, Integer> call(Tuple2<Integer, String> line)
throws Exception {
return new Tuple2<String, Integer>(line._2,line._1);
}
}). collect();;
//注意:当使用本地的local[*>1]的时候,使用foreach遍历数据的时候会出错?
//具体的什么问题我也不是很清楚?
/**
foreach(new VoidFunction<Tuple2<String,Integer>>() {
private static final long serialVersionUID = 1L;
public void call(Tuple2<String, Integer> tuple) throws Exception {
System.out.println(tuple);
}
});
**/
for(Tuple2<String, Integer> list1:temp){
System.out.println(list1);
}
//关闭SparkContext
sparkContext.stop();
}
}

思考:假如有1亿条数据,如何过滤掉出现次数最多的字符串:抽样-wordcount统计-调换(K,V)-排序取Top1-filter过滤即可。
scala版本的思考题代码:

package spark.myspark.functions
import org.apache.spark.{SparkContext, SparkConf}
//思考:假如有1亿条数据,如何动态的统计出出现次数最多的编程语言,然后过滤掉
// 思路:抽样-wordcount统计-调换(K,V)-排序取Top1-filter过滤即可。
/**
* 使用到的算子:
* sample
* flatmap
* map
* reduceByKey
* sortByKey
* take(n)-----Action算子
* first()----源码中即take(1)
* filter
*/
object Sample_test {
def main(args: Array[String]) {
val conf= new SparkConf().setAppName("sample").setMaster("local")
val context =new SparkContext(conf)
val textRDD= context.textFile("words.txt")
//抽样
val sampleRDD=textRDD.sample(false,0.9)
//拿到编程语言---(语言,1)---根据key求和---转换(语言,出现次数)--(次数,语言)---排序---取Top1---取Top1对应的编程语言
val WordRDD= sampleRDD.map(x=>{(x.split(" ")(1),1)}).reduceByKey(_+_)
//first=take(1)----Action类的算子,返回一个非RDD的值
val code= WordRDD.map(x=>{(x._2,x._1)}).sortByKey(false).first()._2
//过滤
textRDD.filter(x=>{!x.contains(code)}).foreach(println)
context.stop()
}
}

注意:有多少个Action类的算子就有多少个Job任务
reduceByKey和sortByKey会产生Shuffle
注意:一个Spark应用程序的编写流程
详细请参考: “戏”说Spark-Spark Stage切分
"戏"说Spark-Spark Shuffle详解
补充:依赖包及源码包:链接: http://pan.baidu.com/s/1nuTS8WT 密码:9bf7
1:源码包下载地址(包含依赖包):
技能补充:
如何使用Idea以maven的方式编译源码包
1:下载源码,地址: http://spark.apache.org/downloads.html ,选择相应的版本

2:将源码工程import到Idea
3:以maven的方式构建,可能需要等2-3小时,需要下载Spark相关的依赖包
如何使用Eclipse查看源码?
1:下载源码
2:Ctrl需要查看的类,然后选择源码包即可查看
思维导图构建你的知识体系:

参考:
http://www.jianshu.com/p/c7eef3eb6225

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spark中的RDD(Resilient Distributed Datasets)是一种分布式的数据结构,它可以被分割成多个分区,每个分区可以在不同的节点上进行计算。RDD提供了一系列的转换操作函数,可以对RDD进行各种操作RDD转换函数包括map、filter、flatMap、union、distinct、groupByKey、reduceByKey、sortByKey等。这些函数可以对RDD进行转换操作,生成新的RDDRDD操作函数包括count、collect、reduce、take、foreach等。这些函数可以对RDD进行操作,返回结果或者将结果输出到外部系统。 在使用RDD时,需要注意一些问题,如RDD的惰性计算、RDD的持久化、RDD的分区等。同时,还需要根据实际情况选择合适的RDD转换操作函数,以达到最优的计算效果。 总之,Spark中的RDD转换操作函数是非常重要的,掌握它们可以帮助我们更好地使用Spark进行分布式计算。 ### 回答2: Spark是一个基于内存计算的分布式计算框架,可以实现大规模数据集的快速处理。在Spark中,RDD(弹性分布式数据集)是数据处理的核心概念,它是一种可以分区、并行计算和容错的不可变数据结构。而Spark中的函数式编程模型则将RDD转换操作都看做是函数的调用,从而简洁明了,易于理解和操作。 在Spark中,解决一个具体问题通常涉及一系列RDD转换操作RDD转换包括对原有RDD进行过滤、映射、聚合等处理,得到新的RDD操作则是对新的RDD进行输出、保存、统计、排序等操作。以下介绍几种常见的RDD转换操作函数。 1. map函数 map函数是一种转换函数,它可以将一个RDD中每个元素通过一个用户定义的函数映射到另一个RDD中,并得到新的RDD。例如,将一个整型RDD中的每个元素都乘以2后得到一个新的整型RDD: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val rdd2 = rdd1.map(x => x*2) ``` 2. filter函数 filter函数也是一种转换函数,它可以根据用户定义的条件过滤一个RDD中的元素,并得到一个新的RDD。例如,将一个字符串RDD中长度大于5的元素过滤出来得到一个新的字符串RDD: ``` val rdd1 = sc.parallelize(Array("hello", "world", "spark", "rdd")) val rdd2 = rdd1.filter(x => x.length > 5) ``` 3. reduce函数 reduce函数是一种操作函数,它可以将一个RDD中的元素按照用户定义的函数进行聚合并得到一个结果。例如,将一个整型RDD中的所有元素相加得到一个整数结果: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val result = rdd1.reduce((x, y) => x + y) ``` 4. collect函数 collect函数也是一种操作函数,它可以将一个RDD中的所有元素收集起来并输出到Driver端。然而,使用collect函数需要注意RDD的大小,如果RDD很大,就可能会出现内存溢出的情况。例如,将一个整型RDD中的所有元素收集起来并输出到屏幕: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val result = rdd1.collect() result.foreach(println) ``` 5. saveAsTextFile函数 saveAsTextFile函数也是一种操作函数,它可以将一个RDD中的所有元素保存到指定的文本文件中。例如,将一个字符串RDD中的所有元素保存到hdfs的一个文本文件中: ``` val rdd1 = sc.parallelize(Array("hello", "world", "spark", "rdd")) rdd1.saveAsTextFile("hdfs://localhost:8020/user/abc/output") ``` 总之,Spark中的RDD转换操作函数具有弹性、高效、简单等特点,能够满足各种大规模数据处理需求。需要特别注意的是,Spark中的函数式编程模型是基于JVM的,因此要充分利用内存和CPU资源,需要对集群配置和调优进行一定的优化和测试。 ### 回答3: Spark中的RDD(Resilient Distributed Datasets)是分布式的弹性数据集,它可以在大规模集群上并行化地计算,并且提供了一系列的转换操作函数。其中,Spark提供的Spark函数简单易用,具有高效的数据处理能力,可以帮助开发者快速开发分布式应用程序。 RDD转换函数是将一个RDD转换成另一个RDD的函数,转换后的RDD通常包含了数据处理、筛选和过滤后的新数据集,可以用来接着进行后续的计算。 例如,map函数可以将RDD中的每个元素应用一个函数,然后返回一个新的转换过的RDD: ``` val originalData = sc.parallelize(List(1, 2, 3, 4, 5)) val mappedData = originalData.map(x => x * 2) ``` 这里,map函数将原始数据中的每个元素都乘上了2,返回了一个新的RDD。 除了map函数, 还有flatMap、filter、groupBy等常用的转换函数,都可以帮助我们对RDD做出各种各样的数据处理和转换RDD操作函数则是对RDD进行真正的计算操作,例如reduce、count、collect等函数,这些函数会触发Spark的分布式计算引擎执行真正的计算任务。 比如,reduce函数可以将RDD中的所有元素进行聚合,返回一个单一的结果: ``` val originalData = sc.parallelize(List(1, 2, 3, 4, 5)) val reducedData = originalData.reduce(_ + _) ``` 这里,reduce函数将原始数据中的所有元素进行相加操作,返回了一个整数类型的结果。 Spark提供的操作函数非常丰富,从基本的聚合、排序、统计操作,到高级的机器学习和图形处理等操作,开发者可以根据不同的业务需求灵活选择使用。 总之,Spark中的RDD转换操作函数是分布式数据处理的核心之一,通过这些函数,开发者能够方便地对海量数据进行分布式的计算和处理。同时,Spark也提供了丰富的API和工具,便于开发者进行高效的Spark应用程序开发。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值