Spark中RDD是一个不可变的分布式对象集合,每个RDD都被分为多个分区,这些分区被分发到集群的不同的节点中进行计算。
SparkContext是Spark的编程主入口点,可以被用于在集群中创建RDDs,在spark-shell中被系统默认创建为sc。
两种创建RDD的方式:(1)调用SparkContext的parallelize()方法将数据并行化成RDD
(2)从外部存储系统(eg.HDFS、共享文件系统、Hbase等)引用数据成RDD
首先还是打开集群,进入到spark-shell
通过调用SparkContext的parallelize方法将驱动程序已经存在的数据集转化为并行化集合Parallelized Collections).。
集合的元素被复制以形成可并行操作的分布式数据集。
例如,下面创建一个包含数字 1~5的并行集合:
一旦创建,分布式数据集(distData) 就可以进行并行操作。例如,我们可以调用distData.reducel(a, b)=> a + b)将数组的
元素相加。
并行集合的一个重要参数是将 数据集切割到的分区数(artitions) ,Spark 将为集群的每个RDD分区运行一个计算任务(task),
即RDD每个分区是计算任务的基本分配单位,而非整个RDD。通常,Spark 会根据集群实际情况自动设置分区数。
但是,也可以通过将其作为第二个数传递给paralice来手动设置,如下实例欲将data数据集切分为10个分区。
而实际开发中更多的是从外部数据源读取来创建RDD。
读取:读取后的RDD都是由String对象组成的RDD[String],然后就可以通过变量people调用RDD类中的定义的方法。
有关Spark的textFile0读取文件的一一些注意事项如下:
①如果需从本地文件系统读取文件作为外部数据源,则文件必须确保集群上的所有工作节点可访问。可以将文件复制到
所有工作节点或使用集群上的共享文件系统。
②Spark所有的基于文件的读取方法,包括textFile 支持读取某个目录下多个指定文件,支持部分的压缩文件和通配符。
例如,可以使用textFile("/my/directory/*")读取该目录下所文件,可以采用通配符匹配同一类型文件
textFile(/my/directory/* .txt"),也可以读取压缩文textFilcC/myldirectory/* .gz"),还可以使用
textFil("/myl/irectoreldatat.lxt'","/my/directory/data2.txt)时读取来自不同路径的多个文件。
③该textFile方法还采用可选的第二个参数来控制文件的分区数。默认情况下,Spark 为文件的每个块创建一个分区
(HDFS中默认为128MB),但也可以通过传递更大的值来请求更高数量的分区。请注意,不能有比块少的分区。
同时对于许多小文件的目录,可以采用SparkContext.wholeTextFiles
RDD操作:
RDD支持两种类型的操作:转化操作(transformation) 与行动操作(action)。
collect()不能应用在大规模数据集上。cache()是转化操作,属于惰性计算。
转化操作从一个已存在的RDD创建一个新的RDD:
行动操作在RDD上进行计算后将结果值返回给驱动程序的操作。
例如,map通过遍历RDD的每一个元素,进行相应的用户定义的操作,并返回表示结果的新RDD的转换操(transformation)。
另一方面,reduce 是使用一些函数聚合RDD的所有元素,并将最终结果返回给驱动程序的行动操作(action)。
在此,分辨一个操作到底是转化操作还是行动操作,可以根据返回值类型来直观判断,即转化操作返回值皆为RDD,行动操作
则是表示计算结果的Int、String、Array、List类型返回值(当然也存在例外,例如reduceByKey,其虽为行动操作,但返回的仍
为RDD。
Spark中的所有转换操作都是懒惰计算的,因为它们不会马上计算结果。相反,它们只记住应用于某些基本数据集(RDD)的
转换关系(RDD转化谱系图)。 只有当某个行动操作需要将结果返回给驱动程序时才会真正进行转换计算。这种设计使Spark
能够更高效地运行。例如,我们可以认识到,通过对创建的RDD依次调用map、reduce 操作,返回到驱动程序的仅是经过
map、reduce 最终处理后的结果(很小的结果集),而不是经map操作后的很大的映射数据集,这也反映出了惰性求值在大数
据分析领域的合理性。
默认情况下,被重用的中间结果RDD可能会在每次对其进行行动操作时重新计算。但是,可以使用persist (cache)方法在内存
中保留被重用的中间结果RDD,在这种情况下,Spark将在集群内存上保留该RDD,以便在下次查询时进行更快的访问。还支持
在磁盘上持久存储RDD。
============================================================================================
转化操作实例:
经常用到的两个转化操作是map()和filter(), 这两者的共同点在于会触发对RDD中所有元素进行遍历。转化操作map()接收
一个函数,把这个函数用于RDD中的每个元素,将函数的返回结果作为结果RDD中对应元素的值。而转化操作filter()则
接收一个函数, 并将RDD中满足该函数的元素放入新的RDD中返回。
map实例:
filter实例:
详解上面的占位符:
(1) import导入包的所有成员,相当于Java的*。inporn scala.math._。比Java方便的一点是它可以导入某个类下的所有静态
成员,Java 则需要impar static。
(2)占位符,来表示某一个参数, 这个用法比较多。比如对collection,sequence或者本章所学的RDD调用方法
map、filter、foreach等对每一个元素进行处理,可以使用_表示每一个元素, 例如map(_.func);还有参数推导时f(250*_)
(3)对变量进行默认初始化,下划线代表的是某一类型的默认值, 对于Int来说,它是0。对于Double来说,它是0.0.对于
引用类型,它是null.比如var i:Int_.
(4)访问tuple (元组)的某个元素时通过索引n来取得第n个元素,可以用方法_1,_2,_3访问组员, 如a._2。
(5)向函数或方法传入可变参数时,不能直接传入Range 或集合或数组对象,需要使用: _*转换才可传入。
(6)类的cter方法,比如类A中定义了var f.则相当于定义了seter 方法f_=.当然你可以自己定义f_=方法来完成更多的事情,比如
设置前做一些判断或预处理之类的操作。
flatMap实例:
flatMap和map操作皆是传入func对RDD每个元素进行处理的操作,不同点在于 map(func)传入的func在处理RDD的
每一个元素后都产生相对应的结果,而正是由这些一 一对应的结果值组成了输出RDD,而flatMap(func)的传入func在
处理每一个元素时,都可能会产生一个或多个对应的元素组成的返回值序列的迭代器,输出的RDD倒不是由迭代器组
成的,而是一个包含各个迭代器可访问所有元素的RDD。因此,当我们希望对每个输入元素生成多个输出元素,可以
使用flatMap。
集合操作:distinct. union. intersection, subtract. cartesian
尽管RDD本身不是严格意义上的集合,但它也支持许多数学上的集合操作,比如合并(union)、相交(intersection)、
作差(subtract)、 去重(distinct). 笛卡儿积cartesian) 操作,值得注意的是,这些操作都要求操作涉及的RDD[T]是相同
数据类型的。
动作操作:
注意不论哪种情况,都可以使用foreach()动作操作来对RDD中的每个元素进行操作,而无需把RDD发回本地。
其他实战案例见:https://blog.csdn.net/qq_25948717/article/details/81912785