RDD是一些对象的只读集合, 被划分到多台机器上, 并且在某个划分块丢失之后可以重建. 用户可以显式的把RDD缓存在内存中, 方便在类似于Map-Reduce的并发操作中重用, 这也是为什么Spark比较适合处理迭代式Job的原因. RDD通过"血统"(lineage)的概念来保证容错性, 当RDD的一个划分块丢失之后, 该RDD知道怎样从其他的RDD中重建该划分块. RDD中的元素不需要被存储在物理设备上, 每个RDD都有一个句柄, 其中包含了如何从其他存储在物理设备上的数据计算该RDD的信息.
RDD有两种类型: 并行集合和Hadoop数据集. 可以在两种类型上执行相同的方法.
在一个Scala集合(一个 Seq 对象)上调用 SparkContext 的 parallelize() 方法就可以得到并行集合. 该集合中的元素会被拷贝, 构成一个分布式的数据集, 然后可以对其进行并发的操作. 下例为基于一个 array 构造并发集合:
在构造完成之后, 这个分布式的数据集就可以进行并行的操作. 比如调用 distData.reduce(_ + _) 来对数组中的元素求和.
并行集合的一个重要的参数是数据集被切片的个数. Spark会对每个切片运行一个task. 通常来说对于每个CPU需要有2-4个切片. 一般情况下, Spark会根据集群的状况自动设置数据集的切片数, 但是可以通过 sc.parallelize(data,10) 来设置.
Spark可以基于在HDFS(或者AmazonS3, Hypertable, HBase)等分布式文件系统创建分布式数据集. Spark支持文本文件, Sequence File等Hadoop输入格式.
对于文本文件, 可以使用 SparkContext 的 textFile() 方法. 该方法的参数为文本文件的URI:
一旦创建完毕, 可以在 distFile 上执行并行操作: distFile.map(_.size).reduce(_ + _)
默认情况下, Spark会为文本文件的每一个块创建一个切片, 也可以像之前的并发数据集一样设置切片数, 但是切片的个数不能少于文件块的个数.
对于Sequence File, 可以使用 SparkContext 的 sequenceFile[K,V] 方法, 其中K和V是文件中的键与值的类型.
RDD支持两种操作: transformation和action.
transformation会基于一个RDD生成一个新的RDD. Spark中的transformation是惰性的(lazy), 亦即transformation不会立刻计算出其结果, 只有当一个action需要在transformation生成的RDD上得到结果并返回给驱动程序时才会计算. 这种设计使得Spark可以更加高效的运行: 对于一个由map生成, 并且会执行一个reduce操作的数据集, 只有reduce的结果需要返回给驱动程序, 而不是该数据集.
默认情况下, 每当你需要在一个被transformation生成的数据集上执行操作时, 该数据集都需要被重新计算. 但是, 我们可以把该数据集用 persist 或者 cache 方法persist在内存中, 这样这个在下次访问该数据集时速度会大大加快.
action会返回 驱动程序 (driver program)一个值. 驱动程序实现了应用程序高层控制流, 并且会并行的执行操作.
常用的transformation操作有
常用的action操作有
Spark中, 用户可以显式的把RDD缓存(persist, 或cache)在内存中. 当缓存一个RDD时, 每个节点都会把计算出的那个切片存储在内存中, 并且会在之后的action中重用这个切片. 这样之后的action就会更快.
可以调用RDD的 persist() 或者 cache() 来进行缓存. 当该RDD第一次被计算出来时, 就会存储在内存中. 这种缓存是由容错性的, 如果RDD的某个块丢失了, 则会根据产生这个RDD的transformation来生成这个块.
每个RDD可以使用不同的存储级别, 可以把这个数据集存储在硬盘, 或者以序列化的Java对象的形式存储在内存中, 或者在多个节点上进行备份. 可以通过向 persist() 方法传递 org.apche.spark.storage.StorageLevel 来选择存储级别. cache() 方法相当于是选择了 StorageLevel.MEMORY_ONLY (以序列化的对象的身份存储在内存中). 以下是完整的存储级别
关于选择存储级别的一些思路
Spark存储级别是为了在内存使用和CPU效率之间做权衡.
1. RDD的类型
RDD有两种类型: 并行集合和Hadoop数据集. 可以在两种类型上执行相同的方法.
1.1 并行集合(Parallelized Collections).
在一个Scala集合(一个 Seq 对象)上调用 SparkContext 的 parallelize() 方法就可以得到并行集合. 该集合中的元素会被拷贝, 构成一个分布式的数据集, 然后可以对其进行并发的操作. 下例为基于一个 array 构造并发集合:
在构造完成之后, 这个分布式的数据集就可以进行并行的操作. 比如调用 distData.reduce(_ + _) 来对数组中的元素求和.
并行集合的一个重要的参数是数据集被切片的个数. Spark会对每个切片运行一个task. 通常来说对于每个CPU需要有2-4个切片. 一般情况下, Spark会根据集群的状况自动设置数据集的切片数, 但是可以通过 sc.parallelize(data,10) 来设置.
1.2 Hadoop数据集
Spark可以基于在HDFS(或者AmazonS3, Hypertable, HBase)等分布式文件系统创建分布式数据集. Spark支持文本文件, Sequence File等Hadoop输入格式.
对于文本文件, 可以使用 SparkContext 的 textFile() 方法. 该方法的参数为文本文件的URI:
一旦创建完毕, 可以在 distFile 上执行并行操作: distFile.map(_.size).reduce(_ + _)
默认情况下, Spark会为文本文件的每一个块创建一个切片, 也可以像之前的并发数据集一样设置切片数, 但是切片的个数不能少于文件块的个数.
对于Sequence File, 可以使用 SparkContext 的 sequenceFile[K,V] 方法, 其中K和V是文件中的键与值的类型.
2. RDD的操作
RDD支持两种操作: transformation和action.
transformation会基于一个RDD生成一个新的RDD. Spark中的transformation是惰性的(lazy), 亦即transformation不会立刻计算出其结果, 只有当一个action需要在transformation生成的RDD上得到结果并返回给驱动程序时才会计算. 这种设计使得Spark可以更加高效的运行: 对于一个由map生成, 并且会执行一个reduce操作的数据集, 只有reduce的结果需要返回给驱动程序, 而不是该数据集.
默认情况下, 每当你需要在一个被transformation生成的数据集上执行操作时, 该数据集都需要被重新计算. 但是, 我们可以把该数据集用 persist 或者 cache 方法persist在内存中, 这样这个在下次访问该数据集时速度会大大加快.
action会返回 驱动程序 (driver program)一个值. 驱动程序实现了应用程序高层控制流, 并且会并行的执行操作.
常用的transformation操作有
- map(func) 对输入并行数据集中的每个元素都执行func, 生成新的并行数据集
- filter(func) 对输入并行数据集中的每个元素, 如果func返回值为 trus , 则在输出并行数据集中保留该元素, 否则过滤.
- flatMap(func) 类似于map, 只是每个输入元素可能被映射到0个或者多个输出元素(所以func用该返回一个 Seq 而不是单个元素)
- mapPartitions(func) 类似于map, 但是是在RDD的每个划分块上单独执行. 所以func的类型为 Iterator[T] =>Iterator[U]
- mapPartitionsWithSplit(func) 类似于mapPattitions, 但是会在func的参数中加一个整数来表示split块的索引 (Int,Iterator[T]) => Iterator[U]
- sample(withReplacement, fraction, seed) 从数据中抽样fraction比例的样本.
- union(otherDataset) 合并输入数据集和参数中指定的数据集
- distinct([numTasks]) 返回一个数据集, 只包含输入数据集中互不相同的元素
- groupByKey([numTasks]) 当输入数据集包含的是(K,V)对时, 返回(K, Seq[V]), 默认numTasks为8
- reduceByKey(func, [numTasks]) 当输入数据集包含的是(K,V)对时, 返回(K, V), 相当于是先对(K, V)执行groupByKey, 再对每个K的Seq[V]执行func.
- sortByKey([ascending], [numTasks]) 按照K排序, 其中K需要实现Ordered
- join(otherDataset, [numTasks]) 将输入数据集(K, V)和另外一个数据集(K, W)进行Join, 得到(K, (V, W))
- cogroup(otherDataset, [numTasks]) 将输入数据集(K, V)和另外一个数据集(K, W)进行cogroup, 得到一个格式为(K, Seq[V], Seq[W])的数据集
- cartesian(otherDataset) 做笛卡尔积: 对于数据集T合U, 得到(T, U)格式的数据集
常用的action操作有
- reduce(func) 对数据集的所有元素执行聚集(func)函数, 该函数必须是可交换的
- collect() 将数据集中的所有元素以一个array的形式返回
- count() 返回数据集中元素的个数
- first() 返回数据集中的第一个元素, 类似于take(1)
- take(n) 返回一个包含数据集中前n个元素的数组, 当前该操作不能并行.
- takeSample(withReplacement, num, seed) 返回包含随机的num个元素的数组.
- saveAsTextFile(path) 把数据集中的元素写到一个文本文件. Spark会对每个元素调用toString方法来把每个元素存成文本文件的一行.
- saveAsSequenceFile(path) 把数据集中的元素存成Hadoop SequenceFile的格式. 只有当RDD的格式为键值对时才可以.
- countByKey() 只有当RDD的格式为键值对时才可以. 返回一个(K, Int)的map, Int为K的个数.
- foreach(func) 对数据集中的每个元素都执行func.
3. RDD的持久化
Spark中, 用户可以显式的把RDD缓存(persist, 或cache)在内存中. 当缓存一个RDD时, 每个节点都会把计算出的那个切片存储在内存中, 并且会在之后的action中重用这个切片. 这样之后的action就会更快.
可以调用RDD的 persist() 或者 cache() 来进行缓存. 当该RDD第一次被计算出来时, 就会存储在内存中. 这种缓存是由容错性的, 如果RDD的某个块丢失了, 则会根据产生这个RDD的transformation来生成这个块.
每个RDD可以使用不同的存储级别, 可以把这个数据集存储在硬盘, 或者以序列化的Java对象的形式存储在内存中, 或者在多个节点上进行备份. 可以通过向 persist() 方法传递 org.apche.spark.storage.StorageLevel 来选择存储级别. cache() 方法相当于是选择了 StorageLevel.MEMORY_ONLY (以序列化的对象的身份存储在内存中). 以下是完整的存储级别
- MEMORY_ONLY 以反序列化Java对象的心事存储在内存, 如果RDD太大不能完全放在内存, 则多余的一些划分块不会被存储, 会在需要时现生成
- MEMORY_AND_DISK 以反序列化Java对象的心事存储在内存, 如果RDD太大不能完全放在内存, 则把多余的划分块存储在硬盘
- MEMORU_ONLY_SER 以序列化的Java对象的形式存储在内存. 这样比比反序列化Java对象回省空间, 但是费CPU
- MEMORY_AND_DISK_SER 顾名思义, 以序列化Java对象的行书存储在内存, 多余的块存储在硬盘上
- DISK_ONLY 把RDD存储在硬盘
- MEMORY_ONLY_2, MEMORY_AND_DISK_2 与以上的存储级别类似, 但是会备份2份
关于选择存储级别的一些思路
Spark存储级别是为了在内存使用和CPU效率之间做权衡.
- 最好使用默认的存储级别(MEMORY_ONLY), 这是CPU效率最好的选项, 使RDD上的操作尽可能快
- 如果RDD比较大不能存储在内存, 则尝试MEMORY_ONLY_SER, 并且选择一个块的序列化库, 使得既能节省空间, 又不太影响速度.
- 除非计算数据集的代价很高或者生成该数据集会过滤掉很多数据, 否则不要把数据存储在硬盘, 因为重新计算一个划分块比从硬盘中读取要快很多.
- 当需要快速容错时, 使用带备份的存储级别. 虽然所有的存储级别都可以通过重新计算丢失的数据来达到容错, 但是备份可以使得无需重新计算就能继续在RDD上执行task.
- 转载:http://www.kemaswill.com/system/spark/spark%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%89-rdd%E5%BC%B9%E6%80%A7%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E9%9B%86/