spark RDD 笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013066244/article/details/80769297

环境

spark:2.3.1
java:1.8
Hadoop:2.7.6

前言

个人笔记

概念

在较高层次,每个Spark应用都是由driver program(驱动程序)组成,其中驱动程序就是运行用户main函数并在集群上执行各种并行操作。Spark提供的主要抽象就是RDD,它是跨群集节点分区的元素集合,可以并行操作。
RDDs是在Hadoop文件系统(或任何其他Hadoop支持的文件系统)中的文件或者在驱动程序中已有的Scala集合中开始创建的,并对其进行转换。
用户也可以要求Spark在内存中持久化RDD,以便在并行操作中有效地重用它。最后一点,RDD可以自动从故障节点中恢复(个人认为可能这就是取名Resilient的原因吧!)。

spark第二个抽象是可用于并行操作的共享变量。默认情况下,当spark在不同节点上并行运行一个函数作为一组任务时,它会将该函数中使用到的每个变量的副本发送给每个任务。有时候,变量需要在任务之间或者 任务与驱动程序之间共享。
spark支持两种类型的共享变量:广播变量broadcast variables,其可以在所有节点的内存中缓存变量值。另一个变量是accumulators(累加器),其只能添加到变量中去,例如 计数和总和。

spark是围绕RDD的概念展开的,个人理解,感觉,spark可能是基于RDD而开发的(但又不完全对)。
RDD是可以并行操作的容错元素集合。其全称为Resilient Distributed Datasets(可复原的分布式数据集)

创建RDDs

有两种方式可以创建RDDs

方式一、 Parallelized Collections

在你的驱动程序中,并行化一个现有的集合。

并行化集合通过在驱动程序中的现有集合上调用JavaSparkContext的并行化方法来创建:
集合中的每个元素会被复制形成一个可以并行操作的分布式数据集。例如下面对数字1到5是如何创建一个并行集合的。

List<Integer> data = Arrays.asList(1, 2, 3, 4, 5);
JavaRDD<Integer> distData = sc.parallelize(data);

一旦创建,分布式数据集(disData)将可以并行操作。例如,我们可以调用distData.reduce((a, b) -> a + b)来使列表中的元素相加。
并行集合的一个很重要参数是将数据集(dataset)切成分区数量(有多少个分区,就把数据集分割成多少块)。Spark将为集群中的每个分区运行一个任务。通常,希望集群中的每个CPU使用2-4个分区。通常情况下,spark会参数根据你的集群自动设置分区数量。但是你也可以将其作为第二个参数传入parallelize 来手动设置(例如:sc.parallelize(data, 10))。
注意:代码中的一些地方使用术语切片(分区的同义词)来维持向后兼容性。

方式二、External Datasets

在外部存储系统中,引用一个数据集。如共享文件系统,HDFSHBase或提供Hadoop InputFormat的任何数据源。

Spark可以从Hadoop支持的任何存储源创建分布式数据集,包括本地文件系统,HDFSCassandraHBaseAmazon S3

Spark支持 文本文件, SequenceFiles和任何Hadoop inpuFormat

Text file RDDs可以使用SparkContext’s textFile方法来创建。该方法为该文件提供一个URI(亦或是机器的本地路径或者是一个 hdfs://, s3a://,等等)并读取它作为集合中的行。如下:
一旦创建,distFile可以操作数据集。例如,我们可以使用mapreduce,将计算所有行加起来的大小:distFile.map(s -> s.length()).reduce((a, b) -> a + b)

基础代码

//从外部文件中定义了一个基本的 RDD
JavaRDD<String> lines = sc.textFile("data.txt");
//定义了 lineLengths 作为 map transformation 的结果。
//请注意,由于 laziness(延迟加载)lineLengths 不会被立即计算
JavaRDD<Integer> lineLengths = lines.map(s -> s.length());
//运行reduce,这是一个 action
//此时,Spark 分发计算任务到不同的机器上运行,每台机器都运行 map 的一部分并本地运行 reduce,
//仅仅返回它聚合后的结果给驱动程序
int totalLength = lineLengths.reduce((a, b) -> a + b);

想将RDD持久化到内存:

lineLengths.persist(StorageLevel.MEMORY_ONLY());

将函数传递给Spark

java而言,有两种方式
1、将一个实现了接口的实例传递给spark或者使用匿名内部类。
2、使用lambda

使用lambda方式

JavaRDD<String> lines = sc.textFile("data.txt");
JavaRDD<Integer> lineLengths = lines.map(s -> s.length());
int totalLength = lineLengths.reduce((a, b) -> a + b);

使用匿名内部类的方式

JavaRDD<String> lines = sc.textFile("data.txt");
JavaRDD<Integer> lineLengths = lines.map(new Function<String, Integer>() {
  public Integer call(String s) { return s.length(); }
});
int totalLength = lineLengths.reduce(new Function2<Integer, Integer, Integer>() {
  public Integer call(Integer a, Integer b) { return a + b; }
});

在自己的类中实现相应的接口,再将实例传递进去

class GetLength implements Function<String, Integer> {
  public Integer call(String s) { return s.length(); }
}
class Sum implements Function2<Integer, Integer, Integer> {
  public Integer call(Integer a, Integer b) { return a + b; }
}

JavaRDD<String> lines = sc.textFile("data.txt");
JavaRDD<Integer> lineLengths = lines.map(new GetLength());
int totalLength = lineLengths.reduce(new Sum());

猜你喜欢

转载自blog.csdn.net/u013066244/article/details/80769297