Spark期末复习(二)RDD

spark核心编程RDD

RDD概述

弹性分布式数据集,代表一个弹性的、不可变的、可分区、里面的元素可并行计算的集合

  • 弹性
    • 存储的弹性:内存与磁盘相互切换
    • 容错的弹性:数据丢失可以自动恢复
    • 计算的弹性:计算出错重试机制
    • 分片的弹性:可根据需要重新分片
  • 分布式:数据存储在大数据集群的不同节点上
  • 数据集:RDD封装了计算逻辑,并不保存数据
  • 数据抽象:RDD是一个抽象类,需要子类具体实现
  • 不可变:RDD封装了计算逻辑,是不可以改变的,想要改变,只能产生新的RDD,在新的RDD里面封装计算逻辑
  • 可分区、并行计算

五大属性:

  • Partition:一组分片,数据集的基本组成单位。可以在创建RDD时指定RDD的分片个数。每个RDD会被一个计算任务处理,相互之间没有影响
  • 分区函数:
  • RDD之间的依赖关系:依赖关系分为宽依赖和窄依赖。部分数据丢失后,可以通过依赖关系重新计算
  • Partitioner:分片函数/分区器:两种类型的分区函数:
    • 基于哈希的Hash Partition,
    • 基于范围的Range Partition。
    • 只有对于key-value的RDD才会有partitioner。
  • Preferred location:每个partition的优先位置

执行原理
spark执行时,先申请资源,然后将应用程序的数据处理逻辑分解为一个一个的计算任务,将计算任务分发到已经分配了资源的计算节点上,按照指定的计算模型进行数据计算,最后得出计算结果

RDD工作原理(在yarn上)

  • 启动yarn集群
  • spark通过申请资源申请调度节点和计算节点
  • spark框架根据需求将计算逻辑根据分区划分成不同的任务
  • 调度节点将任务根据计算节点状态发送到队形的计算节点进行计算

RDD的创建

  1. 从文件中创建::
    • sc.textfile():以行为单位读取数据,读取的数据都是字符串
    • sc.wholeTextFiles():以文件为单位
  2. 从内存中读取数据
  3. 通过并行集合(数组)创建:
    1. sc.parallelize()
    2. sc.markRDD()
  4. 分区:一行一行读取并分区,与子结束没关系,与偏移量有关系

RDD的操作

transformation

只发生转换

  • filter:
    val lines: RDD[String] = sc.textFile("data/01.txt")
    val result: RDD[String] = lines.filter(lines => lines.contains("spark"))
    result.collect().foreach(println)
    
  • map:一个数据一个数据执行,分区内顺序执行,分区之间并行
	val list: List[Int] = List(1, 2, 3)
    val rdd: RDD[Int] = sc.makeRDD(list)
    val result2: RDD[Int] = rdd.map(_ * 2)
    result2.collect().foreach(println)
  • mappartition:以分区为单位转换操作,将整个分区加载到内存中进行引用

    • 传递一个迭代器,返回一个迭代器
    • 内存占用较高
  • mapPartitionWithIndex

  • flatmap:
    与map的区别:

  • groupByKey:返回一个新的(K,Iterable)形式的数据集(无参数传入)

	val lines: RDD[String] = sc.textFile("data/01.txt")
    val words: RDD[(String, Iterable[Int])] = lines.flatMap(_.split(" "))
          .map(x => (x, 1))
          .groupByKey()
	words.collect().foreach(println)

运行结果:
在这里插入图片描述

  • reduceByKey(func)
    val lines: RDD[String] = sc.textFile("data/01.txt")
    val words: RDD[(String, Int)] = lines.flatMap(_.split(" "))
      .map(x => (x, 1))
      .reduceByKey((a, b) => a + b)
    words.collect().foreach(println)

运行结果:
在这里插入图片描述

Action

  • count():统计RDD个数
  • collect():执行
  • take(int):
  • foreach():对每一个RDD执行一样的操作
	val array: Array[Int] = Array(1, 2, 3, 4, 5)
    val rdd: RDD[Int] = sc.parallelize(array)
    val count: Long = rdd.count()
    val first: Int = rdd.first()
    val take: Array[Int] = rdd.take(1)
    val reduce: Int = rdd.reduce((a, b) => a + b)
    println(count)
    println(first)
    println(reduce)

运行结果:
在这里插入图片描述

惰性机制:调用action中的函数才执行计算

RDD分区

分区可以增加程序的并行度,实现分布式计算

  • 分区原则:分区个数 = 集群中CPU核心数目
  • 如何分区:
    • local模式:默认本地机器CPU数目
    • Standlone模式/yarn模式:默认值大于2
    • Apache Mesos模式:默认分区数为8
    • 手动分区:
      1. 创建RDD时指定分区数量:sc.textFile(path,partitionNum)
      2. 使用reparitition方法重新设置分区:val rdd = data.repartition(2)mo

RDD的持久化和checkpoint

持久化

为了重用,或数据计算时间较长或数据较重要时使用持久化
使用cache() 或 persist()
cache默认保存到内存中
存储到磁盘:persist(storage Level.DISK_ONLT)
级别有不同:

  • 仅在内存中缓存,且溢出不写入磁盘,丢弃:MEMORY_NOLY
  • 仅写入磁盘:DISK_ONLY
  • 仅写入磁盘,副本为2:MEMORY_ONLY_2
  • 写入内存,内存不够溢写磁盘:MEMORY_AND_DISK
    val lines: RDD[String] = sc.textFile("data/01.txt",2)
    val wordcount: RDD[(String, Int)] = lines.flatMap(_.split(" ")).map(x => (x, 1))
      .reduceByKey((a, b) => a + b)
    wordcount.cache()
//    wordcount.persist()
    wordcount.collect().foreach(println)

check point

检查点路径中保存的文件,执行完毕后不会被删除
设置保存路径:
sc.setCheckpointDir(“”)

check point与 cache对区别:

  • cache将数据存储在内存中进行数据重用,会在血缘关系中添加新的依赖,出现问题从头读取
  • persist将数据存储在磁盘文件中进行重用,涉及到io,性能较低,但数据安全。如果job执行完毕,临时保存的数据文件就会丢失
  • check point将数据长久地保存在磁盘文件中进行数据重用,为了数据安全,一般会独立进行。为了提高效率,一般需要与cache联合使用:
rdd.cache()    
rdd.checkpoint()
  • checkpoint在执行过程中会切断血缘关系,重新建立新的血缘关系,等同于改变数据源

RDD的分区

**分区的作用:**增加程序的并行度,实现分布式计算

分区个数 = 集群中CPU核心数目
但Apache Mesos模式中,分区个数默认为8

设置分区数:创建RDD时可手动指定:
val rdd = parallelize(array,2)
或通过repartition方法修改分区个数

    val size: Int = wordcount.partitions.size
    val repartitionRDD: RDD[(String, Int)] = wordcount.repartition(4)
    val size2: Int = repartitionRDD.partitions.size

    println(size)
    println(size2)

运行结果:在这里插入图片描述

分区类型

  • HashPartitioner(哈希分区)
  • RangerPartitioner(区域分区)
  • 自定义分区

自定义分区器:

  • 继承org.apache.spark.Partitioner
  • numPartitions:Int 返回创建出来的分区数
  • getPartiton(key: Any):Int 返回分区索引,从0开始
  • 定义分区的函数
  • 示例:根据key值的最后一位数字,写到不同的文件中:
package com.dw.rdd

import org.apache.spark.rdd.RDD
import org.apache.spark.{Partitioner, SparkConf, SparkContext}

object testPartitioner {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("MyPartitioner")
    val sc: SparkContext = new SparkContext(conf)

    val data: RDD[Int] = sc.parallelize(1 to 20)
    data.map((_, 1)).partitionBy(new Mypartitioner(10)).map(_._1).saveAsTextFile("data/partitioner")
  }

}

class Mypartitioner(numPartition: Int) extends Partitioner{
  override def numPartitions: Int = numPartition

  override def getPartition(key: Any): Int = {
    key.toString.toInt % 10
  }
}

键值对RDD

键值对RDD的创建

  1. 读取文件 => flatmap分词 => map构成键值对(_,1)
  2. 读列表 => map构成键值对(_,1)

##键值对RDD的操作
3. reduceByKey:相同key的值进行汇总求和``
4. groupByKey:相同key的值进行分组,但不汇总求和
5. 分别实现wordcount:
通过reduceByKey实现:

    rdd = sc.textfile(“”)
    word = rdd.flatmap(line => line.split(‘ ‘)).map((_,1))
    WordCount = word.reduceByKey(_+_)

通过groupByKey实现:

    ```
    rdd = sc.textfile(“”)
    word = rdd.flatmap(line => line.split(‘ ‘)).map((_,1))
    WordCount = word.groupByKey.map(x => (_.1,X.2.sum))
    ```
  1. 将所有的key返回生成一个新的RDD:rdd.keys
  2. 将所有的value返回生成一个新的RDD:rdd.values
  3. sortByKey():返回一个根据键排序的RDD
  4. sortBy():自定义根据什么东西排序
  5. map Values(func):对每一个value都应用func函数
  6. join:把RDD中元素key相同的进行连接

RDD的数据读取

本地文件系统数据读写

读:sc.textFile(“”)
写:rdd.saveAsTextFile(“”)

分布式文件系统HDFS的数据读取

读:sc.textFile(“”)
写:rdd.saveAsTextFile(“”)

json文件的数据读写

读:sc.textFile(“”)
解析:JSON.parseFull(JsonString:String)
解析成功返回:Some(map: Map[String,Any])
解析失败返回:None

综合案例

综合案例

package com.dw.rdd

import org.apache.spark.rdd.RDD
import org.apache.spark.{HashPartitioner, SparkConf, SparkContext}

object sort {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("sort")
    val sc: SparkContext = new SparkContext(conf)
    sc.setCheckpointDir("checkpoint")

    var index: Int = 0
    val lines: RDD[(String, String)] = sc.wholeTextFiles("data/sort", 3)
    val result: RDD[(Int, Int)] = lines.filter(_.trim().length > 0.)
      .map(x => (x.trim().toInt, " "))
      .partitionBy(new HashPartitioner(1))
      .sortByKey()
      .map(x => {
        index = index + 11
        (index, x._1)
      })
    result.saveAsTextFile("data/sortoutput")
//    result.collect().foreach(println)
    sc.stop()
  }

}

  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spark RDD(弹性分布式数据集)是Spark最基本的数据结构之一,它是一个不可变的分布式对象集合,可以在集群进行并行处理RDD可以从Hadoop文件系统读取数据,也可以从内存的数据集创建。RDD支持两种类型的操作:转换操作和行动操作。转换操作是指对RDD进行转换,生成一个新的RDD,而行动操作是指对RDD进行计算并返回结果。RDD具有容错性,因为它们可以在节点之间进行复制,以便在节点故障时恢复数据。 Spark RDD的特点包括: 1. 分布式:RDD可以在集群进行并行处理,可以在多个节点上进行计算。 2. 不可变性:RDD是不可变的,一旦创建就不能修改,只能通过转换操作生成新的RDD。 3. 容错性:RDD具有容错性,因为它们可以在节点之间进行复制,以便在节点故障时恢复数据。 4. 惰性计算:RDD的计算是惰性的,只有在行动操作时才会进行计算。 5. 缓存:RDD可以缓存到内存,以便在后续操作快速访问。 Spark RDD的转换操作包括: 1. map:对RDD的每个元素应用一个函数,生成一个新的RDD。 2. filter:对RDD的每个元素应用一个函数,返回一个布尔值,将返回值为true的元素生成一个新的RDD。 3. flatMap:对RDD的每个元素应用一个函数,生成一个新的RDD,该函数返回一个序列,将所有序列的元素合并成一个新的RDD。 4. groupByKey:将RDD的元素按照key进行分组,生成一个新的RDD。 5. reduceByKey:将RDD的元素按照key进行分组,并对每个分组的元素进行reduce操作,生成一个新的RDDSpark RDD的行动操作包括: 1. count:返回RDD元素的个数。 2. collect:将RDD的所有元素收集到一个数组。 3. reduce:对RDD的所有元素进行reduce操作,返回一个结果。 4. foreach:对RDD的每个元素应用一个函数。 5. saveAsTextFile:将RDD的元素保存到文本文件。 以上就是Spark RDD的详细介绍。 ### 回答2: Apache Spark是一款基于内存的分布式计算系统,可以处理大规模数据,其最为重要的就是SparkRDD(Resilient Distributed Datasets,弹性分布式数据集),RDDSpark的基本数据结构,是一种类似于数组的分布式数据集,可以被分割成多个分区,并在集群的多个节点间进行并行计算。RDDSpark提高执行效率和数据可靠性的重要手段。 在SparkRDD具有以下三个特点:弹性、不可变和可分区。弹性指RDD能够自动进行数据分区和容错,即使节点出现故障,也能够自动从故障的节点复制数据,提高了数据的可靠性和并行计算的效率。不可变指RDD一旦创建就不能够被改变,可以进行转换操作生成新的RDD,也可以被缓存到内存以供重复使用。可分区则指RDD可以被分成多个分区,实现并行计算。 SparkRDD的API提供了丰富的操作方法,常见的操作包括:转换操作和动作操作。转换操作指对RDD进行转换操作,返回一个新的RDD对象,例如map()、filter()等;动作操作指对RDD进行计算并返回结果,例如reduce()、collect()等。 值得注意的是,RDD是一种惰性求值的数据结构,即当对RDD进行转换操作时并不会立即进行计算,而是当需要对RDD进行动作操作时才会进行计算,这种惰性求值的机制可以进一步提高Spark的效率。同时,为了提高计算效率,可以使用RDD的持久化(缓存)功能,将RDD持久化到内存,以便复用。 总之,RDDSpark的核心数据结构,其弹性、不可变和可分区的特点以及丰富的API操作方法,为Spark实现高效计算和数据处理提供了重要的支持。 ### 回答3: Spark RDDSpark的核心抽象,代表分布式的元素集合,支持多种操作和转换。RDD可以看作是一个不可变的分布式内存数据集合,由一些分布式的partition(分区)组成。 1. RDD的特性: - 分布式的数据集,可以跨越多个节点进行计算 - 可以并行处理,充分利用集群计算资源 - 不可变的数据集,任何对数据集的操作都会生成新的数据集 - 支持多种类型的转换操作,如map、filter、reduce、groupByKey等 2. RDD的创建: - 通过外部数据源创建RDD:从HDFS或其他存储系统读取数据创建 - 通过程序的数据结构创建RDD:从内存的数据结构创建 - 通过其他RDD转换创建RDD:通过对已有的RDD进行转换操作创建 3. RDD的转换: RDD支持多种类型的操作和转换,如map、filter、reduce、groupByKey等。这些转换操作不会立即执行,而是记录下来,等到需要输出结果时才会真正执行。 4. RDD的行动: 行动操作是指对RDD进行计算并返回结果的操作,如count、collect等。行动操作会立即触发RDD的计算过程。 5. RDD的缓存: RDD支持缓存操作,将一个RDD的结果缓存在内存,提高后续对该RDD的计算效率。缓存可以在计算过程多次使用,通过unpersist清理缓存。 6. RDD的持久化: 当RDD的计算过程非常复杂时,可以将计算过程得到的RDD进行持久化以便后续使用。持久化可以选择将RDD保存在磁盘或者内存,也可以将RDD复制到多个节点上以保障数据的可靠性。 7. RDD的checkpoint: RDD的checkpoint是指将RDD的计算结果保存在HDFS或其他分布式存储系统,以便后续查询和还原数据集。在计算复杂的RDD时,使用checkpoint可以避免计算过程数据丢失的问题。 总的来说,Spark RDDSpark分布式计算的核心特性,其提供对大规模数据集的分布式处理能力,以及丰富的操作和转换方式,使得程序员可以轻松地处理海量数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值