Spark学习之RDD编程(一)

RDD是Spark的核心概念,它是一个可读的、可分区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,可在多次计算间重用。Spark用Scala语言实现了RDD的API,我们可以通过调用API实现对RDD的各种操作,从而实现各种复杂的应用。

RDD创建

Spark采用textFile()方法从文件系统中加载数据创建RDD,该方法把文件的URI作为参数,这个URI可以是本地文件系统的地址、分布式文件系统HDFS的地址

1.从本地文件系统中加载数据

在spark--shell交互环境中,执行如下命令:

其中,“lines:org.apache.spark.rdd.RDD[String]......"是命令执行返回的信息,从中可以看出,执行sc.textFile()方法以后,Spark从本地文件word.txt中加载数据到内存,在内存中生成一个RDD对象lines,lines是org.apache.spark.rdd.RDD这个类的一个实例,这个RDD里面包含了若干个元素,每个元素的类型是String类型,也就是说,从word.txt文件中读取出来的每一行文本内容,都成为RDD中的每一个元素,如果word.txt中包含了1000行,那么,lines这个RDD中就会包含1000个String类型的元素。

2.从分布式文件系统HDFS中加载数据

从HDFS中加载数据的命令如下:

3.通过并行集合(数组)创建RDD

可以调用SparkContext的parallelize方法,从一个已经存在的集合(数组)上创建RDD,命令如下:

 

RDD操作 

RDD操作包括两种类型,即转换(Transformation)操作和行动(Action操作)。

  • 转换操作

对于RDD而言,每一次转换操作都会产生不同的RDD,供给下一个操作使用。RDD的转换过程是惰性求值的,也就是说,整个转换过程只是记录了转换的轨迹,并不会发送真正的计算,只有遇到行动操作时,才会触发"从头到尾”真正的计算。下表给出了常用的RDD转换操作API,其中很多都是高阶函数,比如,filter(func)就是一个高阶函数,这个函数的输入参数func也是一个函数。

操作 含义
filter(func) 筛选出满足func的元素,并返回一个新的数据集
map(func) 将每个元素传递到函数func中,并将结果返回为一个新的数据集
flatMap(func) 与map()相似,但每个输入元素都可以映射到0或多个输出结果
groupByKey() 应用于(K,V)键值对的数据集时,返回一个新的(K,Iterable)形式的数据集
reduceByKey(func) 应用于(K,V)键值对的数据集时,返回一个新的(K,V)形式的数据集,其中每个值是将每个key传递到函数func中进行聚合后的结果
  • filter(func)

filter(func)操作会筛选处满足函数func的元素,并返回一个新的数据集。例如:

执行lines.filter()操作,filter()的输入参数line=>line.contains("Spark")是一个匿名函数。line.filter(line=>line.contains("Spark“))操作的含义是,依次取出lines这个RDD中的每一个元素,对于当前取到的元素,把它赋值给匿名函数式中的line变量,然后,执行匿名函数体部分line.contains("Spark"),如果line中包含"Spark"这个单词,就把这个元素加入到新的RDD(即linesWithSpark)中,否则,就丢弃该元素。最终,新生成的RDD中的所有元素,都包含了单词"Spark"。

  • map(func)

map(func)操作将每个元素传递到函数func中,并将结果返回一个新的数据集。

第一行语句创建了一个包含5个Int类型元素的数组array。第2行语句执行sc.parallelize(0,从数组array中生成一个RDD,即rdd1,rdd1中包含5个Int类型的元素,即1、2、3、4、5。第三行语句执行rdd1.map()操作,map()的输入参数"x=>x+10"是一个匿名函数。依此取出rdd1中的每个元素,分别+10,作为函数的返回值,并作为一个元素放入到新的RDD(即rdd2)中。

  • flatMap(func)

flatMap(func)与map()相似,但每个输入元素都可以映射到0或多个输出结果。例如

第一步:map()。执行lines.map(line=>line.split(" ")操作,从lines转换得到一个新的RDD(即wordArray),wordArray中的每个元素都是一个数组对象。例如,第1个元素是Array("Hadoop","is","good"),第2个元素是Array("Spark","is","fast"),第三个元素是Array("Sark","is","better")。

第二步:拍扁(flat)。flatMap()操作中的flat是一个很形象的动作——”拍扁",也就是把wordArray中的每个RDD元素都拍扁成多个元素,最终,所有这些被拍扁以后得到的元素,构成一个新的RDD,即words。

  • groupByKey()

groupByKey()应用于(K,V)键值对的数据集时,返回一个新的(K,Iterable)形式的数据集。

 如上所示L("is",1)("is",1)这2个键值对的key相同,归并为一个新的键值对("is",(1,1))

  • reduceByKey(func)

reduceByKey(func)应用于(K,V)键值对的数据集时,返回一个新的(K,V)形式的数据集,其中的每个值是将每个key传递到函数func中进行聚合后得到的结果。

所有key相同的键值对,它们的value首先被归并到一起,然后使用func函数把(1,1)聚合在一起。

2.行动操作

行动操作是真正触发计算的地方。Spark程序只有执行到行动操作时,才会执行真正的计算,从文件中加载数据,完成一次又一次转换操作,最终,完成行动操作得到结果。下表列出了常用的RDD行动操作API。

操作 含义
count() 返回数据集中的元素个数
collect() 以数组的形式返回数据集中的所有元素
first() 返回数据集中的第一个元素
take(n) 以数组的形式返回数据集中的前n个元素
reduce(func) 通过函数func(输入两个参数并返回一个值)聚合数据集中的元素
foreach(func) 将数据集中的每个元素传递到函数func中运行

当采用Local模式在单击上执行时,rdd.foreach(println)语句会打印出一个RDD中的所有元素。但是,当采用集群模式执行时,在Worker节点上执行打印语句到Worker不会现实打印语句的这些输出内容的。

3.惰性机制 

所谓的“惰性机制”是指,整个转换过程只是记录了转换的轨迹,并不会发送真正的计算,只有遇到行动操作时,才会触发“从头到尾:的真正计算。

持久化

在Spark中,RDD采用惰性求值的机制,每次遇到行动操作,都会从头开始计算。每次遇到行动操作,都会触发一次从头开始的计算,对于迭代计算而言,代价是很大的,因为迭代计算经常需要多次重复使用同一组数据。下面就是多次计算同一个RDD的例子:

实际上,可以通过持久化(缓存)机制来避免这种重复计算的开销。具体方法是使用persist()方法对一个RDD标记尾持久化,之所以说”标记为持久化“,是因为出现persist()语句的地方,并不会马上计算生成RDD并把它持久化,而是要等到遇到第一个行动操作触发真正计算以后,才会把计算结果进行持久化,持久化后的RDD将会被保留在计算节点的内存中,被后面的行动操作重复使用。

persist()的圆括号中包含的是持久化级别参数,可以有如下不同的级别:

  • persist(MEMORY_ONLY):表示将RDD作为反序列化的对象存储于JVM中,如果内存不足,就按照LRU原则替换缓存中的内容; 
  •  persist(MEMORY_AND_DISK):表示将RDD作为反序列化的对象存储在JVM中,如果内存不足,超出的分区将会被存放在磁盘上。

持久化RDD会占用内存空间,当不再需要一个RDD时,就可以使用uppersist()方法手动地把持久化的RDD从缓存中移除,释放空间内存。

猜你喜欢

转载自blog.csdn.net/qq_41338249/article/details/84772628