【Spark四十】RDD算子逻辑执行图第一部分

本文深入探讨Spark的RDD算子,包括count、groupByKey、join、union和reduceByKey。重点关注Shuffle过程,如ShuffleMapTask和ResultTask的数据交互,以及reduceByKey的map端预reduce操作。通过分析逻辑执行图,揭示了ShuffleDependency如何聚合相同key的数据,并介绍combineByKey函数及其在数据聚合与计算中的作用。

 

1.count
2.groupByKey
3.join
4.union
5.reduceByKey

 

Shuffle/Dependency总结

 

ShuffleMapTask将数据写到内存(或者磁盘)供ResultTask来拉取,那么写的策略是什么?ResultTask怎么知道拉取属于它的数据,那么这里头Mapper和Reducer应该通力协作,工作完成数据的写和读操作。

 

1. count

  /**
   * Return the number of elements in the RDD.
   */
  def count(): Long = sc.runJob(this, Utils.getIteratorSize _).sum

Utils.getIteratorSize算出一个worker上的elements的数目,然后然后通过sum操作,将所有worker节点上的elements数目进行相加

先在每个 partition 上执行 count,然后执行结果被发送到 driver,最后在 driver 端进行 sum。

 

2. groupByKey

 

package spark.examples

import java.util.Random

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.SparkContext._

/**
 * Usage: GroupByTest [numMappers] [numKVPairs] [valSize] [numReducers]
 */
object SparkGroupByTest {
  def main(args: Array[String]) {
    val sparkConf = new SparkConf().setAppName("GroupBy Test").setMaster("local ")
    val numMappers = 1//100
    val numKVPairs = 100//00
    val valSize = 10//00
    val numReducers = 36

    val sc = new SparkContext(sparkConf)

   ///定义numMappers个元素的集合,对每个元素调用flatMap操作
    val pairs1 = sc.parallelize(0 until numMappers, numMappers).flatMap { p =>

     ///随机数,作为arr1的元素类型(K,V)中的K
      val ranGen = new Random

     ///定义一个数组,长度为numKVPairs。元素类型是(K,V)的二元组,K的类型是Int,V的类型是字节数组(字节长度为valSize)
      val arr1 = new Array[(Int, Array[Byte])](numKVPairs)

     ///对长度为numKVPairs的arr1进行填充值
      for (i <- 0 until numKVPairs) {

        ///创建数组元素的字节数组,数组长度为valSize
        val byteArr = new Array[Byte](valSize)
        ranGen.nextBytes(byteArr)
        //K是随机生成的整数
        arr1(i) = (ranGen.nextInt(Int.MaxValue), byteArr)
      }
      arr1
    }.cache
    // Enforce that everything has been calculated and in cache

   //action操作,将数据缓存,并且返回所有的(K,V)对
    println(pairs1.toDebugString);
    /*cache的是FlatMappedRDD
    FlatMappedRDD[1] at flatMap at SparkGroupbyTest.scala:26 [Memory Deserialized 1x Replicated]
    ParallelCollectionRDD[0] at parallelize at SparkGroupbyTest.scala:26 [Memory Deserialized 1x Replicated]
     */

    pairs1.count

    ///根据Reducer个数做groupBy操作,
    println(pairs1.groupByKey(numReducers).count)

    sc.stop()
  }
}

 

 

1. groupByKey的含义是对(K,V)进行合并。

例如:

节点1: (1,2),(1,3),(2,6)

节点2: (1,7),(3,8),(2,9)

那么groupByKey结束后得到的结果是什么?

(1,(2,7)),(1,(3,7)),(2,(6,9)), (3,(_,8))? 不对,最后的结果,应该是Key是唯一的

 

2. 上面的例子中,reducer的个数是36,那么要做group操作,所以,来自各个worker节点的相同的Key必须由同一个reducer上来处理,这是怎么做到的?即reducer拉取数据时,是按照Key做Hash么?hash(key)%36. 即m个mapper结果,由r个reducer消费,如何消费?每个mapper都有reducer的数据,reducer如何拉取应该由它处理的这些数据?从不同的mapper中拉取数据,这就是Shuffle Write的工作!是分布式计算框架的核心之一

3. 如下图所示:ShuffledRDD存放的时比较合并的结果,只是从FlatMappRDD将原始数据拉取过来?拉取数据时,Mapp端没有做预combine操作??

4. groupByKey操作是一个根据Key把所有的Value聚合到一起的操作,这跟SQL的groupBy操作不一样,SQL的groupBy操作的结果是,一组的结果是每个占据一行。

5. groupByKey不要是用map端的combine

 

 /**
   * Group the values for each key in the RDD into a single sequen
在 IDEA 中实现 Spark 相关任务(包括 RDD 基本算子实验和 WordCount 综合实验),需要先设置好开发环境,再基于具体的业务需求编写代码。下面详细介绍如何实现实验内容: ### 第一部分:掌握 RDD 算子的使用 #### 实现步骤 1. **准备环境** - 创建一个 Maven 工程。 - 修改 `pom.xml` 添加 Spark 依赖: ```xml <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.12</artifactId> <version>3.0.1</version> </dependency> ``` 2. **初始化 SparkSession 和 SparkContext** 这是所有 Spark 操作的基础。 ```java import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; public class RddOperatorDemo { private static final String SPARK_MASTER_URL = "local"; public static void main(String[] args) { // 初始化 Spark Context SparkConf conf = new SparkConf().setAppName("RddOperator").setMaster(SPARK_MASTER_URL); JavaSparkContext sc = new JavaSparkContext(conf); rddOperators(sc); // 调用算子练习函数 sc.close(); // 关闭上下文 } /** * 测试各种 RDD 转换算子与行动算子的功能 */ private static void rddOperators(JavaSparkContext sc) { List<String> wordsList = Arrays.asList("hello", "world", "hello spark", "hadoop"); // 生成初始 RDD JavaRDD<String> initialRDD = sc.parallelize(wordsList); // map 示例:将每个单词转成大写形式 System.out.println("--- Map Operator ---"); JavaRDD<String> mappedRDD = initialRDD.map(s -> s.toUpperCase()); mappedRDD.collect().forEach(System.out::println); // distinct 示例:去重操作 System.out.println("\n--- Distinct Operator ---"); JavaRDD<String> distinctRDD = initialRDD.distinct(); distinctRDD.collect().forEach(System.out::println); // flatMap 示例:对字符串按空格拆分出单个词语集合 System.out.println("\n--- FlatMap Operator ---"); JavaRDD<String> flattenWordsRDD = initialRDD.flatMap(s -> Arrays.asList(s.split(" ")).iterator()); flattenWordsRDD.collect().forEach(System.out::println); // filter 示例:过滤掉长度小于等于4的元素 System.out.println("\n--- Filter Operator ---"); JavaRDD<String> filteredRDD = flattenWordsRDD.filter(word -> word.length() > 4); filteredRDD.collect().forEach(System.out::println); // reduceByKey & mapValues 示例:词频统计前处理阶段 System.out.println("\n--- ReduceByKey and MapValues Operators ---"); JavaPairRDD<String, Integer> pairRDD = flattenWordsRDD.mapToPair(word -> new Tuple2<>(word, 1)); JavaPairRDD<String, Integer> reducedRDD = pairRDD.reduceByKey((v1, v2) -> v1 + v2); reducedRDD.collect().forEach(tuple -> System.out.println(tuple._1 + ": " + tuple._2)); // groupByKey 示例:按照 key 分组值列表 System.out.println("\n--- GroupByKey Operator ---"); JavaPairRDD<String, Iterable<Integer>> groupedRDD = pairRDD.groupByKey(); groupedRDD.collect().forEach(entry -> System.out.printf("%s => %s\n", entry._1(), Lists.newArrayList(entry._2()))); // sortByKey 示例:按键排序键值对 System.out.println("\n--- SortByKey Operator ---"); JavaPairRDD<Integer, String> invertedPairsRDD = flattenedWordsRDD.mapToPair(word -> new Tuple2<>(word.hashCode(), word)); invertedPairsRDD.sortByKey(true).collect().forEach(pair -> System.out.println(pair._2())); } } ``` --- ### 第二部分:Spark 算子综合实验 —— WordCount (词频统计) #### 实现步骤 1. 同样在上面基础上继续新增一段针对 WordCount 的完整代码逻辑。 ```java public static void runWordCountExample(JavaSparkContext sc){ String inputFilePath = "/path/to/input/text/file"; // 替换为实际输入路径 JavaRDD<String> linesRDD = sc.textFile(inputFilePath); // 加载文本数据作为行级 RDD // 单词分割、映射到(key,value) JavaRDD<String> allWords = linesRDD.flatMap(line -> Arrays.asList(line.toLowerCase().split("\\W+")).iterator()); JavaPairRDD<String,Integer> pairs = allWords.mapToPair(word->new Tuple2<>(word,1)); // 计算每种词汇的数量总计 JavaPairRDD<String,Integer> counts = pairs.reduceByKey(Integer::sum); // 输出最终结果集 counts.foreach(tup->{System.out.println(tup._1()+" : "+tup._2());}); } ``` 2. 最后记得修改主方法调用新加入的任务入口: ``` public static void main(String[] args) { ... runWordCountExample(sc); ...} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值