第二章:《Spark之-----RDD编程》摘要

一、普通RDD

一、从文件系统中加载数据创建RDD
1.读取本地文件:

scala> val lines = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt")

2.读取HDFS里面的文件

scala> val lines = sc.textFile("hdfs://localhost:9000/user/hadoop/word.txt")

二、通过并行集合(数组)创建RDD
从数组中创建:

scala>val array = Array(1,2,3,4,5)
scala>val rdd = sc.parallelize(array)

或者,也可以从列表中创建:

scala>val list = List(1,2,3,4,5)
scala>val rdd = sc.parallelize(list)


三、RDD操作
1.转换操作:

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

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
scala> val lines = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt")
scala> lines.map(line => line.split(" ").size).reduce((a,b) => if (a>b) a else b)

reduce()操作每次接收两个参数,取出较大者留下,然后再继续比较直到留出最大值。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
2.行动操作

  • count() 返回数据集中的元素个数
  • collect() 以数组的形式返回数据集中的所有元素
  • first() 返回数据集中的第一个元素
  • take(n) 以数组的形式返回数据集中的前n个元素
  • reduce(func) 通过函数func(输入两个参数并返回一个值)聚合数据集中的元素
  • foreach(func) 将数据集中的每个元素传递到函数func中运行*
    在这里插入图片描述
    在这里插入图片描述


四、持久化
persist()的圆括号中包含的是持久化级别参数,比如,

  • persist(MEMORY_ONLY)如果使用这条语句,内存不足时,就要按照LRU原则替换缓存中的内容。
  • persist(MEMORY_AND_DISK)如果内存不足,超出的分区将会被存放在硬盘上。
  • RDD.cache()=RDD.persist(MEMORY_ONLY)
scala> val list = List("Hadoop","Spark","Hive")
scala> val rdd = sc.parallelize(list)
scala> rdd.cache()  //会调用persist(MEMORY_ONLY)
scala> println(rdd.count()) //第一次行动操作,触发一次真正从头到尾的计算,这时才会执行上面的rdd.cache(),把这个rdd放到缓存中
3
scala> println(rdd.collect().mkString(",")) //第二次行动操作,不需要触发从头到尾的计算,只需要重复使用上面缓存中的rdd
Hadoop,Spark,Hive

最后,可以使用unpersist()方法手动地把持久化的RDD从缓存中移除。



词频统计实例
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


六、打印元素
一般会采用语句rdd.foreach(println)或者rdd.map(println)。
当采用集群模式执行时rdd.collect().foreach(println)来打印,或者rdd.take(100).foreach(println)这种抓取前100条打印。



二、键值对RDD

.一、键值对RDD的创建
①第一种创建方式:从文件中加载

scala>  val lines = sc.textFile("file:///usr/local/spark/mycode/pairrdd/word.txt")
scala> val pairRDD = lines.flatMap(line => line.split(" ")).map(word => (word,1))
scala> pairRDD.foreach(println)
(i,1)
(love,1)
 ...

②通过并行集合来创建键值对RDD

scala> val list = List("Hadoop","Spark","Hive","Spark")
scala> val rdd = sc.parallelize(list)
scala> val pairRDD = rdd.map(word => (word,1))
scala> pairRDD.foreach(println)
(Hadoop,1)
(Spark,1)
(Hive,1)
(Spark,1)

二、常用的键值对转换操作
常用的键值对转换操作包括reduceByKey()、groupByKey()、sortByKey()、join()、cogroup()等
1.reduceByKey(func)

//有四个键值对(“spark”,1)、(“spark”,1)、(“hadoop”,1)和(“hadoop”,1),对具有相同key的键值对进行合并后的结果就是:(“spark”,2)、(Hive,1)、(“hadoop”,1)
scala> pairRDD.reduceByKey((a,b)=>a+b).foreach(println)
(Spark,2)
(Hive,1)
(Hadoop,1)

2.groupByKey()

//四个键值对(“spark”,1)、(“spark”,2)、(“hadoop”,3)和(“hadoop”,5),采用groupByKey()后得到的结果是:(“spark”,(1,2))和(“hadoop”,(3,5))
scala> pairRDD.groupByKey()
scala> pairRDD.groupByKey().foreach(println)
(Spark,CompactBuffer(1, 1))
(Hive,CompactBuffer(1))
(Hadoop,CompactBuffer(1))

3.keys
会把键值对RDD中的key返回形成一个新的RDD。对四个键值对(“spark”,1)、(“spark”,2)、(“hadoop”,3)和(“hadoop”,5)构成的RDD,采用keys后得到的结果是一个RDD[Int],内容是{“spark”,”spark”,”hadoop”,”hadoop”}。

scala> pairRDD.keys.foreach(println)
Hadoop
Spark
Hive
Spark

4.values
会把键值对RDD中的value返回形成一个新的RDD。比如,对四个键值对(“spark”,1)、(“spark”,2)、(“hadoop”,3)和(“hadoop”,5)构成的RDD,采用keys后得到的结果是一个RDD[Int],内容是{1,2,3,5}。

scala> pairRDD.values.foreach(println)
1
1
1
1

5.sortByKey()

scala> pairRDD.sortByKey()
scala> pairRDD.sortByKey().foreach(println)
(Hadoop,1)
(Hive,1)
(Spark,1)
(Spark,1)
//按字母升序

6.sortBy()

scala>val d1=sc.parllelize(Array(('c',8),('c',17),('a',42),('b',4),('d',9),('e',17),('f',29),('g',21),('b',9)))
scala>d1.reduceByKey(_+_).sortByKey(false).collect
res:Array[(String,Int)]=Array((g,21),(f,29),(e,17),(d,9),(c,27),(b,38),(a,42))
scala>val d1=sc.parllelize(Array(('c',8),('c',17),('a',42),('b',4),('d',9),('e',17),('f',29),('g',21),('b',9)))
scala>d1.reduceByKey(_+_).sortBy(_._2,false).collect
res:Array[(String,Int)]=Array((a,42),(b,38),(f,29),(c,27),(g,21),(e,17),(d,9))
//根据value进行降序排列

7.mapValues(func)
它的功能是,对键值对RDD中的每个value都应用一个函数,但是,key不会发生变化。

//比如,对四个键值对(“spark”,1)、(“spark”,2)、(“hadoop”,3)和(“hadoop”,5)构成的pairRDD,如果执行pairRDD.mapValues(x => x+1),就会得到一个新的键值对RDD,它包含下面四个键值对(“spark”,2)、(“spark”,3)、(“hadoop”,4)和(“hadoop”,6)。
scala> pairRDD.mapValues(x => x+1)
scala> pairRDD.mapValues(x => x+1).foreach(println)
(Hadoop,2)
(Spark,2)
(Hive,2)
(Spark,2)

8.join
对于内连接,对于给定的两个输入数据集(K,V1)和(K,V2),只有在两个数据集中都存在的key才会被输出,最终得到一个(K,(V1,V2))类型的数据集。
pairRDD1是一个键值对集合{(“spark”,1)、(“spark”,2)、(“hadoop”,3)和(“hadoop”,5)},pairRDD2是一个键值对集合{(“spark”,”fast”)},那么,pairRDD1.join(pairRDD2)的结果就是一个新的RDD,这个新的RDD是键值对集合{(“spark”,1,”fast”),(“spark”,2,”fast”)}。

scala> val pairRDD1 = sc.parallelize(Array(("spark",1),("spark",2),("hadoop",3),("hadoop",5)))
scala> val pairRDD2 = sc.parallelize(Array(("spark","fast")))
scala> pairRDD1.join(pairRDD2)
scala> pairRDD1.join(pairRDD2).foreach(println)
(spark,(1,fast))
(spark,(2,fast))

9.一个综合实例
题目:给定一组键值对(“spark”,2),(“hadoop”,6),(“hadoop”,4),(“spark”,6),键值对的key表示图书名称,value表示某天图书销量,请计算每个键对应的平均值,也就是计算每种图书的每天平均销量。

scala> val rdd = sc.parallelize(Array(("spark",2),("hadoop",6),("hadoop",4),("spark",6)))
scala> rdd.mapValues(x => (x,1)).reduceByKey((x,y) => (x._1+y._1,x._2 + y._2)).mapValues(x => (x._1 / x._2)).collect()
res22: Array[(String, Int)] = Array((spark,4), (hadoop,5))

在这里插入图片描述



四、文件系统的数据读写

1.本地文件系统的数据读写

scala> val textFile = sc.textFile("file:///usr/local/spark/mycode/wordcount/word.txt")
scala> textFile.first()


如何把textFile变量中的内容再次写回到另外一个文本文件wordback.txt中:

scala> val textFile = sc.textFile("file:///usr/local/spark/mycode/wordcount/word.txt")
scala> textFile.saveAsTextFile("file:///usr/local/spark/mycode/wordcount/writeback")
//注意,写的时候是指定一个目录,不是一个具体文件,你可以写成textFile.saveAsTextFile("file:///usr/local/spark/mycode/wordcount/writeback.txt")但生成的依旧是一个目录
//写入的这个目录下会包含一些文件,这些文件就是被分区后的数据,如果我们读取一个目录时会读取这个目录下所有的文件(也就是这个目录下所有的数据)

我们如果想再次把数据加载在RDD中

scala> val textFile = sc.textFile("file:///usr/local/spark/mycode/wordcount/writeback.txt")
//我们知道weiteback是一个目录,读取一个目录时会读取这个目录下所有的文件(也就是这个目录下所有的数据)

2.分布式文件系统HDFS的数据读写

scala> val textFile = sc.textFile("hdfs://localhost:9000/user/hadoop/word.txt")
scala> textFile.first()
//执行上面语句后,就可以看到HDFS文件系统中(不是本地文件系统)的word.txt的第一行内容了。

下面,我们再把textFile的内容写回到HDFS文件系统中(写到hadoop用户目录下):

scala> val textFile = sc.textFile("word.txt")
scala> textFile.saveAsTextFile("writeback.txt")
//执行上面命令后,文本内容会被写入到HDFS文件系统的“/user/hadoop/writeback”目录下,该目录下会被生成很多分区的文件存储着各种数据,我们需要再次把writeback.txt中的内容加载到RDD中时,只需要加载这个目录就会加载该目录下所有的文件

当需要再次把writeback.txt中的内容加载到RDD中时:

scala> val textFile = sc.textFile("hdfs://localhost:9000/user/hadoop/writeback.txt")
//如果我们给textFile()函数传递的不是文件名,而是一个目录,则该目录下的所有文件内容都会被读取到RDD中。

猜你喜欢

转载自blog.csdn.net/weixin_45014721/article/details/109721502