Spark RDD 创建和分区规则

RDD的创建和分区规则

1.1 从集合中创建RDD

从集合中创建RDD,主要提供了两种函数:parallelize和makeRDD

需求:创建List集合(集合中元素1234),从集合中创建RDD,并打印输出

package com.xcu.bigdata.spark.core.pg02_rdd.pg021_rdd_create

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


object Spark01_CreateRDD_memory {
  def main(args: Array[String]): Unit = {
    //创建配置文件
     /*
    setMaster: 设置Spark环境的运行位置,如 local 或者 hdfs
    [k]表示运行核数为k个,* 表示用本电脑所有核数
    setAppName:设置当前应用程序的名字
     */
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_memory").setMaster("local[*]")
    //创建SparkContext,该对象是提交的入口
    val sc = new SparkContext(conf)
    //创建一个集合对象
    val list: List[Int] = List(1, 2, 3, 4)
    //方式1:根据集合创建RDD
    val rdd1: RDD[Int] = sc.parallelize(list)
    //打印
    rdd1.foreach(print)
    //换行
    println()
    //方式2:根据集合创建RDD
    val rdd2: RDD[Int] = sc.makeRDD(list)
    rdd2.foreach(print)
    //释放资源
    sc.stop()
  }
}
1.2 从外部系统创建RDD

外部存储系统:本地的文件系统,HDFS、HBase等

目标:从本地文件系统,HDFS创建RDD

package com.xcu.bigdata.spark.core.pg02_rdd.pg021_rdd_create

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


object Spark02_CreateRDD_file {
  def main(args: Array[String]): Unit = {
    //创建配置文件
    val conf: SparkConf = new SparkConf().setAppName("").setMaster("local[*]")
    //创建SparkContext,该对象是提交的入口
    val sc = new SparkContext(conf)
    //从本地文件中读取数据,创建RDD
    val rdd1: RDD[String] = sc.textFile("./input/word.txt")
    //从hdfs上读取文件
    val rdd2: RDD[String] = sc.textFile("hdfs://hadoop201:8020/input")
    //打印输出
    rdd1.foreach(println)
    //释放资源
    sc.stop()
  }
}
2.1 内存分区规则和数据读取规则

创建RDD的方式不一样,分区规则不一样

  • 切片规则
  1. 默认的分区数取决于分配给应用的CPU的核数

  2. 如果指定分区,那么最终分区数就为指定的数目

  • 数据读取规则
	// 源码
    def positions(length: Long, numSlices: Int): Iterator[(Int, Int)] = {
      (0 until numSlices).iterator.map { i =>
        val start = ((i * length) / numSlices).toInt
        val end = (((i + 1) * length) / numSlices).toInt
        (start, end)
      }
    }

数据读取举例:sc.makeRDD(List(1, 2, 3, 4, 5), numSlices = 3)

length:数据长度5,numSlices = 3,i为几号分区
根据以上代码
i ---> (start, end) ---> data
0 ---> (0, 1) ---> 1
1 ---> (1, 3) ---> 2 3
2 ---> (3, 5) ---> 4 5
package com.xcu.bigdata.spark.core.pg02_rdd.pg021_rdd_create

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

/**
 * @Package : com.xcu.bigdata.spark.core.pg02_rdd.pg021_rdd_create
 * @Author : 
 * @Desc : 从集合中创建RDD,并指定分区数
 *       -默认的分区数取决于分配给应用的CPU的核数
 *       -如果指定分区数,那么最终分区数就为指定的数目
 */
object Spark04_Partition_mem {
  def main(args: Array[String]): Unit = {
    //创建配置文件
    val conf: SparkConf = new SparkConf().setAppName("").setMaster("local[*]")
    //创建SparkContext,该对象是提交的入口
    val sc = new SparkContext(conf)
    //从集合中创建RDD
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5), numSlices = 3)
    //保存成文件目的是为了查看分区数
    rdd.saveAsTextFile("./output")
    //释放资源
    sc.stop()

  }
}
2.2 文件分区规则和数据读取规则

从文件中创建RDD,采用的是Haoop的分区和数据读取规则:

  • 文件切片规则:以字节方式来切片

切片举例:例如一个文件11个字节,在代码中设置minPartitions=2

minPartitions=2,即预计分为2个分区,但实际有可能不是2个分区

totalSize(文件总字节数) / numSlices(等于minPartitions)= 实际分区个数

11 / 2 = 5 … 1 (1 / 5 )与 0.1 做比较,如果(1 / 5 = 0.2)大0.1, 那么在开一个分区,如果(1 / 5 )小0.1,那么合并到最后一个分区,故实际分区个数为3个

总结:如果指定分区数,那么最后分区数取决于总的字节数是否能够整除预计的最小分区数,并且剩余的字节数达到一个比率

默认分区数取决于:math.min(分配给应用的CPU核数,2)

  • 数据读取规则:以行为单位来读取

数据读取举例:例如一个txt文件10个字节,minPartitions=4

  1. txt文件如下
1
2
3
4
  1. 显示回车和换行,并用符号@代替
# 数据以行的方式读取,但是读取过程中会考虑偏移量(数据的offset)
date=>offset
1@@ => 012
2@@ => 345
3@@ => 678
4 => 9
  1. 计算分区个数

10byte / 4 = 2byte … 2byte =>5个分区,意味着有5个分区,每个分区读取2个字节

每个分区的偏移量为
0 =>(0, 2)
1 =>(2, 4)
2 =>(4, 6) 
3 =>(6, 8)
4 =>(8, 10)
  1. 读取的数据为
分区=>offset =>data
0 =>(0, 2)=> 1  # 实际读取到的offset 0 1 2
1 =>(2, 4)=> 2  # 实际读取到的offset 3 4,上一次读取数据时,把offset=2读走了
2 =>(4, 6)=> 3 # 实际读取到的offset 5 6
3 =>(6, 8)=> 空  # 实际读取到的offset 7 8
4 =>(8, 10)=> 4 # 实际读取到的offset 9
  1. 代码验证
package com.xcu.bigdata.spark.core.pg02_rdd.pg021_rdd_create

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

/**
 * @Package : com.xcu.bigdata.spark.core.pg02_rdd.pg021_rdd_create
 * @Author : 
 * @Desc : 从文件中创建RDD,分区规则和数据读取规则
 */
object Spark05_Partition_file {
  def main(args: Array[String]): Unit = {
    //创建配置文件
    val conf: SparkConf = new SparkConf().setAppName("Spark05_Partition_file").setMaster("local[*]")
    //创建SparkContext,该对象是提交的入口
    val sc = new SparkContext(conf)
    //从集合中创建RDD
    val rdd: RDD[String] = sc.textFile("./input/w.txt", minPartitions = 4)
    //保存成文件目的是为了查看分区数
    rdd.saveAsTextFile("./output")
    //释放资源
    sc.stop()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值