Spark的rdd创建与操作

RDD创建

RDD可以通过两种方式创建:

第一种:读取一个外部数据集,从本地加载数据集或者从HDFS文件系统,HBASE,Cassandra,AmazonS3等外部数据源中加载数据集。

第二种:调用SparkContext的parmallelize方法,在Driver中一个已经存在的集合(数组)上创建。

从文件系统中加载数据创建RDD

Spark采用textfile()方法从文件系统中加载数据创建RDD,该方法把文件的URL作为参数,这个URL可以是本地文件系统的地址,或者是分布式文件系统HDFS的地址,或者是Amazon S3的地址等等。

scala> val lines = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt")
lines: org.apache.spark.rdd.RDD[String] = file:///usr/local/spark/mycode/rdd/word.txt MapPartitionsRDD[12] at textFile at <console>:27

lines是一个String类型的RDD,或者我们以后可以简单称为RDD[String],也就是说,这个RDD[String]里面的元素都是String类型。

在使用Spark读取文件时,需要说明以下几点:
(1)如果使用了本地文件系统的路径,那么,必须要保证在所有的worker节点上,也都能够采用相同的路径访问到该文件,比如,可以把该文件拷贝到每个worker节点上,或者也可以使用网络挂载共享文件系统。
(2)textFile()方法的输入参数,可以是文件名,也可以是目录,也可以是压缩文件等。比如,textFile(“/my/directory”), textFile(“/my/directory/.txt”), and textFile(“/my/directory/.gz”).
(3)textFile()方法也可以接受第2个输入参数(可选),用来指定分区的数目。默认情况下,Spark会为HDFS的每个block创建一个分区(HDFS中每个block默认是128MB)。你也可以提供一个比block数量更大的值作为分区数目,但是,你不能提供一个小于block数量的值作为分区数目。

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

可以调用SparkContext的parallelize方法,在Driver中一个已经存在的集合(数组)上创建。

scala>val array = Array(1,2,3,4,5)
array: Array[Int] = Array(1, 2, 3, 4, 5)
scala>val rdd = sc.parallelize(array)
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[13] at parallelize at <console>:29

从执行结果信息可以看出,rdd是一个Int类型的RDD

RDD操作

RDD被创建好以后,在后续使用过程中一般会发生两种操作:

  •  转换(Transformation): 基于现有的数据集创建一个新的数据集。
  •  行动(Action):在数据集上进行运算,返回计算值。

转换操作

对于RDD而言,每一次转换操作都会产生不同的RDD,供给下一个“转换”使用。转换得到的RDD是惰性求值的,也就是说,整个转换过程只是记录了转换的轨迹,并不会发生真正的计算,只有遇到行动操作时,才会发生真正的计算,开始从血缘关系源头开始,进行物理的转换操作。

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

行动操作

行动操作是真正触发计算的地方,Spark程序执行到行动操作时,才会执行真正的计算,从文件加载数据,完成一次又一次转换操作,最终,完成行动操作得到结果。

下面列出一些常见的行动操作(Action API):

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

惰性机制

scala> val lines = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt")
lines: org.apache.spark.rdd.RDD[String] = file:///usr/local/spark/mycode/rdd/word.txt MapPartitionsRDD[16] at textFile at <console>:27
scala> lines.filter(line => line.contains("Spark")).count()
res1: Long = 2  //这是执行返回的结果

lines就是一个RDD,lines filter()会遍历lines中的每行文本,并对每行文本执行括号中的匿名函数,也就是执行Lambda表达式:line=> line.contains(“spark”) 在执行Lambda表达式时,会把当前遍历到的这行文办内容复制给参数line,然后,执行处理逻辑line.contains(“spark”)。也就是只有当改行文本包含Spark才满足条件,才会被放入结果集中,最后,等到lines集合遍历结束后,就会得到一个结果集,这个结果集包含了所有包含“spark”的行,最后,对这个结果调用count(),这是个行动操作,会计算得出结果集中元素个数。

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)

上面代码中,lines是一个RDD,是String类型的RDD,因为这个RDD里面包含了很多行文本。lines.map(),是一个转换操作,之前说过,map(func):将每个元素传递到函数func中,并将结果返回为一个新的数据集,所以,lines.map(line => line.split(” “).size)会把每行文本都传递给匿名函数,也就是传递给Lamda表达式line => line.split(” “).size中的line,然后执行处理逻辑line.split(” “).size。line.split(” “).size这个处理逻辑的功能是,对line文本内容进行单词切分,得到很多个单词构成的集合,然后,计算出这个集合中的单词的个数。因此,最终lines.map(line => line.split(” “).size)转换操作得到的RDD,是一个整型RDD,里面每个元素都是整数值(也就是单词的个数)。最后,针对这个RDD[Int],调用reduce()行动操作,完成计算。reduce()操作每次接收两个参数,取出较大者留下,然后再继续比较,例如,RDD[Int]中包含了1,2,3,4,5,那么,执行reduce操作时,首先取出1和2,把a赋值为1,把b赋值为2,然后,执行大小判断,保留2。下一次,让保留下来的2赋值给a,再从RDD[Int]中取出下一个元素3,把3赋值给b,然后,对a和b执行大小判断,保留较大者3.依此类推。最终,reduce()操作会得到最大值是5。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值