2.3、从外部存储(文件)创建rdd的个数
-
代码案例
val conf = new SparkConf().setAppName("Simple Application").setMaster("local[*]") val sc = new SparkContext(conf) // 读取本地文件 val readline = sc.textFile("input/1.txt") readline.collect.foreach(println) val par = readline.getNumPartitions println(s"partitions: $par")
-
源码解读
// 读取本地文件 val readline = sc.textFile("input/1.txt") // 点进 textFile def textFile( path: String, minPartitions: Int = defaultMinPartitions): RDD[String] = withScope { assertNotStopped() hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text], minPartitions).map(pair => pair._2.toString).setName(path) } /** textFile方法中有下面这个参数 分区个数 minPartitions: Int = defaultMinPartitions 最小分区数没有指定的 就取defaultMinPartitions 点进 defaultMinPartitions 看看 */ def defaultMinPartitions: Int = math.min(defaultParallelism, 2) /* 这个方法就很明显了 defaultParallelism 和 2 之间取最小值 defaultParallelism 就是之前从集合(内存)中创建rdd中分析的是一样的,都是默认申请的核心数 可以点进去看看 */ def defaultParallelism: Int = { assertNotStopped() taskScheduler.defaultParallelism } /** 但是 有些时候我们会发现,实际的分区个数和我看到的不一样。那是因为 读取文件时 遵循hadoop读取文件划分原则 当总字节数/每个分区字节数的余数 再除以 每个分区字节数 大于0.1 将增加一个分区 详细代码如下: // 数据划分代码 hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text], minPartitions).map(pair => pair._2.toString).setName(path) spark 文件划分主要是调用 Hadoop 中的包 classOf[TextInputFormat] TextInputFormat 进入 */ public class TextInputFormat extends FileInputFormat<LongWritable, Text> implements JobConfigurable {} /* 进入父类FileInputFormat 找到 InputSplit 方法 下面是部分代码 */ public InputSplit[] getSplits(JobConf job, int numSplits) throws IOException { Stopwatch sw = new Stopwatch().start(); FileStatus[] files = listStatus(job); // Save the number of input files for metrics/loadgen job.setLong(NUM_INPUT_FILES, files.length); long totalSize = 0; // compute total size for (FileStatus file: files) { // check we have valid files if (file.isDirectory()) { throw new IOException("Not a file: "+ file.getPath()); } totalSize += file.getLen(); } long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits); long minSize = Math.max(job.getLong(org.apache.hadoop.mapreduce.lib.input. FileInputFormat.SPLIT_MINSIZE, 1), minSplitSize); /* 关键代码 totalSize --> 文件中的字节数 goalSize = totalSize / (numSplits == 0 ? 1 : numSplits) // 每个分区占多少个字节 goalSize = 字节数/ 分区数 实际分区个数 = totalSize / goalSize --> 余数/goalSize > 0.1 商+1(即为实际分区数) 假设字节数为 7 默认分区数为 2: goalSize = 7 / 2 --> 3byte 再根据goalSize计算实际分区数: 实际分区个数 = 7 / 3 --> 2 余数为 1 ; 1/3 = 0.33 所以实际分区数为: 2 + 1 = 3 */
-
总结
文件创建rdd 分区数和hadoop划分数据是一样的
首先根据 默认分区或者指定的分区数计算每个分区的字节量
公式: goalSize = totalSize / (numSplits == 0 ? 1 : numSplits)
描述: 每个分区的字节量 = 总字节数量/ 默认或者指定分区数
根据每个分区的字节量计算实际的分区数
实际的分区数 = totalSize / goalSize 如果余数/goalSize 大于0.1 分区数加1