RDD的Transformation(转换算子)

这篇博客详细介绍了Spark中的RDD Transformation操作,包括value类型、双Value类型和Key-Value类型的转换算子,如map、filter、reduceByKey等,以及它们的功能、使用场景和区别,帮助读者深入理解Spark数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RDD的Transformation(转换算子)

RDD整体上分为Value类型、双Value类型和Key-Value类型

1 value类型

创建包名:com.xiao_after.value

1.1 map()映射

1)函数签名:

def map[U: ClassTag](f: T => U): RDD[U] 

2)功能说明:参数 f 是一个函数,它可以接收一个参数。当某个RDD执行map方法时,

会遍历该RDD中的每一个数据项,并依次应用 f 函数,从而产生一个新的RDD。即,这个

新的RDD中的每一个元素都是原来RDD中每一个元素依次应用 f 函数而得到的。

3)需求说明:创建一个1-4数组的RDD,两个分区,将所有元素*2形成新的RDD

4)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 21:06
 */
object value01_map {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个rdd
    val rdd: RDD[Int] = sc.makeRDD(1 to 4, 2)

    //3.2 调用map方法,每个元素乘以2
    val rdd1: RDD[Int] = rdd.map(_ * 2)

    //3.3 遍历打印输出rdd1
    rdd1.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)输出结果

2
4
6
8
1.2 mapPartitions()以分区为单位执行Map

1)函数签名:

def mapPartitions[U: ClassTag](f: Iterator[T] => Iterator[U]

2)功能说明:Map是依次处理一个元素,而mapPartitions一次处理一个分区数据。

3)需求说明:创建一个RDD,4个元素,2个分区,使每个元素组成新的RDD。

4)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 21:16
 */
object value02_mapPartitions {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3具体业务逻辑
    //3.1 创建一个rdd
    val rdd: RDD[Int] = sc.makeRDD(1 to 4,2)

    //3.2 调用mapPartitions方法,每个元素乘以2
    val rdd1: RDD[Int] = rdd.mapPartitions(_.map(_*2))

    //3.3 遍历打印rdd1中的数据
    rdd1.collect().foreach(println)

    //4.关闭连接
    sc.stop()
    
  }
}

5)输出结果

2
4
6
8
1.3 map()和mapPartitions()区别

1)map():每次处理一条数据;

2)mapPartitions():每次处理一个分区的数据,这个分区的数据处理完后,元RDD分区

中的数据才能释放,可能导致OOM;

3)开发经验:当内存空间较大的时候,建议使用 mapPartitions(),以提高处理效率。

1.4 mapPartitionsWithIndex()带分区号

1)函数签名

  def mapPartitionsWithIndex[U: ClassTag](
      f: (Int, Iterator[T]) => Iterator[U],
      preservesPartitioning: Boolean = false): RDD[U]

2)功能说明:类似于mapPartitions,比mapPartitions多一个整数参数表示分区号

3)需求说明:创建一个RDD,使每个元素跟所在分区号形成一个元组,组成一个新的

RDD

4)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 21:07
 */
object value03_mapPartitionsWithIndex {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(1 to 4, 2)

    //3.2 使每个元素跟所在分区号形成一个元组,组成一个新的RDD
    val rdd1: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex((index, items) => {
      items.map((index, _))
    })

    //3.3 遍历打印rdd1的数据
    rdd1.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)输出结果

(0,1)
(0,2)
(1,3)
(1,4)
1.5 flatMap()扁平化

1)函数签名

  def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U] 

2)功能说明

与map操作类似,将RDD中的每一个元素通过应用f函数依次转换为新的元素,并封装到

RDD中。区别:在flatMap操作中,f函数的返回值是一个集合,并且会将每一个该集合中

的元素拆分出来放到新的RDD中;

3)需求说明:创建一个集合,集合里面存储的还是子集合,把所有子集合中数据取出放

入到一个大的集合中;

4)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 22:55
 */
object value04_flatMap {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[List[Int]] = sc.makeRDD(List(List(1, 2), List(3, 4), List(5, 6), List(7)), 2)

    //3.2 把所有子集合中数据取出放入到一个大的集合中
    val rdd1: RDD[Int] = rdd.flatMap(list => list)

    //3.3 遍历打印rdd1的数据
    rdd1.collect().foreach(println)


    //4.关闭连接
    sc.stop()
  }
}

5)运行结果

1
2
3
4
5
6
7
1.6 glom()分区转换数组

1)函数签名

def glom(): RDD[Array[T]]

2)功能说明:

​ 该操作将RDD中每一个分区变成一个数组,并放置在新的RDD中,数组中元素的类型与

原分区中元素类型一致

3)需求说明:创建一个2个分区的RDD,并将每个分区的数据放到一个数组,求出每个

分区的最大值

4)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 22:56
 */
object value05_glom {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(1 to 4, 2)

    //3.2 求出每个分区的最大值
    val rdd1: RDD[Int] = rdd.glom().map(_.max)

    //3.3 求出所有分区的最大值的和 2 + 4
    println(rdd1.collect().sum)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

6
1.7 groupBy()分组

1)函数签名:

  def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]

2)功能说明:分组,按照传入函数的返回值进行分组。将相同的 key 对应的值放入一个

迭代器

3)需求说明:创建一个RDD,按照元素模以2的值进行分组

4)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 22:56
 */
object value06_groupby {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(1 to 4, 2)

    //3.2 将每个分区的数据放到一个数组并收集到Driver端打印
    rdd.groupBy(_ % 2).collect().foreach(println)
      
    println("--------------------------")

    //3.3 再创建一个RDD
    val rdd1: RDD[String] = sc.makeRDD(List("hello", "hive", "hadoop", "spark", "scala"))

    //3.4 按照首字母第一个单词相同分组
    rdd1.groupBy(str => str.substring(0, 1)).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

(0,CompactBuffer(2, 4))
(1,CompactBuffer(1, 3))
--------------------------
(s,CompactBuffer(spark, scala))
(h,CompactBuffer(hello, hive, hadoop))

注:groupBy会存在shuffle过程;

shuffle:将不同的分区数据进行打乱重组的过程;

shuffle一定会落盘。可以在local模式下执行程序,通过4040看效果。

1.8 GroupBy之WordCount

1)需求说明:创建一个RDD,使用 GroupBy 实现 WordCount 功能

2)具体实现:

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:37
 */
object value07_groupby_wordcount {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val strList: List[String] = List("Hello Scala", "Hello Spark", "Hello World")
    val rdd = sc.makeRDD(strList)

    //3.2 将字符串拆分成一个一个的单词
    val rdd1: RDD[String] = rdd.flatMap(_.split(" "))

    //3.3 将单词结果进行转换,(word) => (word,1)
    val rdd2: RDD[(String, Int)] = rdd1.map((_, 1))

    //3.4 将转换结构后的数据分组
    val rdd3: RDD[(String, Iterable[(String, Int)])] = rdd2.groupBy(_._1)

    //3.5 将分组后的数据进行结构的转换
    val rdd4: RDD[(String, Int)] = rdd3.map {
      case (word, list) =>
        (word, list.size)
    }
    rdd4

    //3.6 遍历打印rdd4
    rdd4.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

3)运行结果

(Hello,3)
(World,1)
(Scala,1)
(Spark,1)
1.9 filter()过滤

1)函数签名

def filter(f: T => Boolean): RDD[T]

2)功能说明

接收一个返回值为布尔类型的函数作为参数。当某个RDD调用filter方法时,会对该RDD中

每一个元素应用f函数,如果返回值类型为true,则该元素会被添加到新的RDD中。

3)需求说明:创建一个RDD,过滤出对2取余等于0的数据

4)代码实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:37
 */
object value08_filter {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(Array(1,2,3,4,5),2)

    //3.2 过滤出符合条件的数据
    val rdd1: RDD[Int] = rdd.filter(_ % 2 == 0)

    //3.3 遍历打印rdd1的数据
    rdd1.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

2
4
1.10 sample()采样

1)函数签名

       def sample(
            withReplacement: Boolean,
            fraction: Double,
            seed: Long = Utils.random.nextLong): RDD[T]
// withReplacement: true为有放回的抽样,false为无放回的抽样;
// fraction表示:以指定的随机种子随机抽样出数量为fraction的数据;
// seed表示:指定随机数生成器种子。

2)功能说明

​ 从大量的数据中采样

3)需求说明:创建一个RDD(1-10),从中选择放回和不放回抽样

4)代码实现

package com.xiao_after.partition

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:37
 */
object value09_sample {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6))

    //3.2
    // 抽取数据不放回(伯努利算法)
    // 伯努利算法:又叫0、1分布。例如扔硬币,要么正面,要么反面。
    // 具体实现:根据种子和随机算法算出一个数和第二个参数设置几率比较,小于第二个参数要,大于不要
    // 第一个参数:抽取的数据是否放回,false:不放回
    // 第二个参数:抽取的几率,范围在[0,1]之间,0:全不取;1:全取;
    // 第三个参数:随机数种子
    val rdd1: RDD[Int] = rdd.sample(false, 0.5)
    rdd1.collect().foreach(println)

    println("-------------------------")

    //3.3
    // 抽取数据放回(泊松算法)
    // 第一个参数:抽取的数据是否放回,true:放回;false:不放回
    // 第二个参数:重复数据的几率,范围大于等于0.表示每一个元素被期望抽取到的次数
    // 第三个参数:随机数种子
    val rdd2: RDD[Int] = rdd.sample(true, 2)
    rdd2.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

1
3
4
-------------------------
1
2
2
2
2
3
4
4
5
5
5
5
6
6
1.11 distinct()去重

1)函数签名:

  def distinct(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] 

2)功能说明:对内部的元素去重,并将去重后的元素放到新的 RDD 中

3)具体实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:38
 */
object value10_distinct {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4,5,4,3,2,1))

    //3.2 对rdd执行去重操作并打印修改后的数据
    rdd.distinct().collect().foreach(println)

    println("-------------------------------")

    //3.3 对rdd采用多个Task去重,提高并发度
    rdd.distinct(2).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

4)运行结果

1
2
3
4
5
-------------------------------
4
2
1
3
5
1.12 coalesce()合并分区

Coalesce算子包括:配置执行Shuffle和配置不执行Shuffle两种方式。

1、不执行Shuffle方式

1)函数签名

def coalesce(numPartitions: Int, shuffle: Boolean = false,  //默认false不执行shuffle
        partitionCoalescer: Option[PartitionCoalescer] = Option.empty)
        (implicit ord: Ordering[T] = null) : RDD[T]

2)功能说明:缩减分区数,用于大数据集过滤后,提高小数据集的执行效率

3)需求:4个分区合并为2个分区

4)代码实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:38
 */
object value11_coalesce {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(Array(1,2,3,4),4)

    //3.2 执行缩减分区操作
    val rdd1: RDD[Int] = rdd.coalesce(2)

    //3.3 查看每个数据的分区编号
    val rdd2: RDD[(Int, Int)] = rdd1.mapPartitionsWithIndex {
      case (index, items) =>
        items.map((index, _))
    }
    rdd2

    //3.4 遍历打印rdd2的数据
    rdd2.collect()foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

(0,1)
(0,2)
(1,3)
(1,4)

2、执行 Shuffle 方式

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4, 5, 6), 3)

    //3.2 执行缩减分区操作
    val rdd1: RDD[Int] = rdd.coalesce(2, true)

运行结果

(0,1)
(0,4)
(0,5)
(1,2)
(1,3)
(1,6)
1.13 repartition()重新分区(执行Shuffle)

1)函数签名

def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]

2)功能说明

该操作内部其实执行的是coalesce操作,参数shuffle的默认值为true。无论是将分区数多

的RDD转换为分区数少的RDD,还是将分区数少的RDD转换为分区数多的RDD,

repartition操作都可以完成,因为无论如何都会经shuffle过程。

3)需求说明:创建一个4个分区的RDD,对其重新分区。

4)代码实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:38
 */
object value12_repartition {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4, 5, 6), 3)

    //3.2 增加分区,不开启shuffle
    val rdd1: RDD[Int] = rdd.coalesce(4)

    //3.3 增加分区,开启shuffle
    val rdd2: RDD[Int] = rdd.coalesce(4, true)

    //3.4 重新分区
    val rdd3: RDD[Int] = rdd.repartition(4)

    //3.5 将修改后的rdd保存在文件夹下
    rdd1.saveAsTextFile("D:\\MyselfPractice\\HdfsClientDemo\\SparkCoreTest\\output6")

    rdd2.saveAsTextFile("D:\\MyselfPractice\\HdfsClientDemo\\SparkCoreTest\\output7")

    rdd3.saveAsTextFile("D:\\MyselfPractice\\HdfsClientDemo\\SparkCoreTest\\output8")

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

output6下面有3个分区,说明这种 coalesce 不开启shuffle来增加分区的方式没有意义
output7下面有4个分区,因为 coalesce 开启了shuffle过程
output8下面有4个分区,因为 repartition 默认开启shuffle 过程
1.14 coalesce和repartition区别

1)coalesce重新分区,可以选择是否进行shuffle过程。由参数shuffle: Boolean =

false/true决定。

2)repartition实际上是调用的coalesce,进行shuffle。源码如下:

def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] = withScope {
    coalesce(numPartitions, shuffle = true)
}

3)coalesce一般为缩减分区,如果扩大分区,不使用shuffle是没有意义的,repartition扩

大分区执行shuffle。

1.15 sortBy()排序

1)函数签名

def sortBy[K]( f: (T) => K,
      ascending: Boolean = true, // 默认为正序排列
      numPartitions: Int = this.partitions.length)
      (implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]

2)功能说明

该操作用于排序数据。在排序之前,可以将数据通过f函数进行处理,之后按照f函数处理

的结果进行排序,默认为正序排列。排序后新产生的RDD的分区数与原RDD的分区数一

致。

3)需求说明:创建一个RDD,按照数字大小分别实现正序和倒序排序

4)代码实现

package com.xiao_after.value

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

/**
 * @author xiaohu
 * @create 2020-09-24 23:39
 */
object value13_sortBy {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[Int] = sc.makeRDD(List(1, 6, 2, 5, 4, 3))

    //3.2 默认是升序排
    val rdd1: RDD[Int] = rdd.sortBy(num => num)

    //3.3 遍历打印rdd1中的数据
    rdd1.collect().foreach(println)

    println("-------------------------")

    //3.4 配置为倒序排
    val rdd2: RDD[Int] = rdd.sortBy(num => num, false)

    //3.5 遍历打印rdd2中的数据
    rdd2.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

1
2
3
4
5
6
-------------------------
6
5
4
3
2
1
1.16 pipe()调用脚本

1)函数签名:

		def pipe(command: String): RDD[String]

2)功能说明

管道,针对每个分区,都调用一次shell脚本,返回输出的RDD。

注意:脚本需要放在Worker节点可以访问到的位置

3)需求说明:编写一个脚本,使用管道将脚本作用于RDD上。

(1)编写一个脚本,并增加执行权限

[xiao@hadoop102 spark-local]$ vim pipe.sh

#!/bin/bash

echo "Start"
while read LINE; do
   echo ">>>"${LINE}
done

[xiao@hadoop102 spark-local]$ chmod 777 pipe.sh

(2)创建一个只有一个分区的RDD

[xiao@hadoop102 spark-local]$ bin/spark-shell
scala> val rdd = sc.makeRDD (List("hi","Hello","how","are","you"), 1)

(3)将脚本作用该RDD并打印

scala> rdd.pipe("/opt/module/spark-local/pipe.sh").collect()
res18: Array[String] = Array(Start, >>>hi, >>>Hello, >>>how, >>>are, >>>you)

(4)创建一个有两个分区的RDD

scala> val rdd = sc.makeRDD(List("hi","Hello","how","are","you"), 2)

(5)将脚本作用该RDD并打印

scala> rdd.pipe("/opt/module/spark-local/pipe.sh").collect()
res19: Array[String] = Array(Start, >>>hi, >>>Hello, Start, >>>how, >>>are, >>>you)

说明:一个分区调用一次脚本。

2 双 Value 类型交互

1)创建包名:com.xiao_after.doublevalue

2.1 intersection()交集

1)函数签名

		def intersection(other: RDD[T]): RDD[T]

2)功能说明

对源RDD和参数RDD求交集后返回一个新的RDD

3)需求说明:创建两个RDD,求两个RDD的交集

4)代码实现

package com.xiao_after.doublevalue

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

/**
 * @author xiaohu
 * @create 2020-09-25 0:53
 */
object DoubleValue01_intersection {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd1: RDD[Int] = sc.makeRDD(1 to 4)

    //3.2 创建第二个RDD
    val rdd2: RDD[Int] = sc.makeRDD(4 to 8)

    //3.3 求两个RDD的交集
    val rdd3: RDD[Int] = rdd1.intersection(rdd2)

    //3.4 遍历打印rdd3中的数据
    rdd3.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

4
2.2 union()并集

1)函数签名:

		def union(other: RDD[T]): RDD[T]

2)功能说明

对源RDD和参数RDD求并集后返回一个新的RDD

3)需求说明:创建两个RDD,求并集

4)代码实现

package com.xiao_after.doublevalue

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

/**
 * @author xiaohu
 * @create 2020-09-25 0:53
 */
object DoubleValue02_union {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd1: RDD[Int] = sc.makeRDD(1 to 4)

    //3.2 创建第二个RDD
    val rdd2: RDD[Int] = sc.makeRDD(4 to 8)

    //3.3 求两个RDD的并集
    val rdd3: RDD[Int] = rdd1.union(rdd2)

    //3.4 遍历打印rdd3中的数据
    rdd3.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }

}

5)运行结果

1
2
3
4
4
5
6
7
8
2.3 subtract()差集

1)函数签名:

		def subtract(other: RDD[T]): RDD[T]

2)功能说明

计算差的一种函数,去除两个RDD中相同元素,不同的RDD将保留下来

3)需求说明:创建两个RDD,求第一个RDD与第二个RDD的差集

4)代码实现

package com.xiao_after.doublevalue

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

/**
 * @author xiaohu
 * @create 2020-09-25 0:53
 */
object DoubleValue03_subtract {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd1: RDD[Int] = sc.makeRDD(1 to 4)

    //3.2 创建第二个RDD
    val rdd2: RDD[Int] = sc.makeRDD(4 to 8)

    //3.3 求两个RDD的差集
    val rdd3: RDD[Int] = rdd1.subtract(rdd2)

    //3.4 遍历打印rdd3中的数据
    rdd3.collect().foreach(println)

    println("---------------------------")

    //3.5 求两个RDD的差集
    val rdd4: RDD[Int] = rdd2.subtract(rdd1)

    //3.6 遍历打印rdd3中的数据
    rdd4.collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }

}

5)运行结果

1
2
3
---------------------------
5
6
7
8
2.4 zip()拉链

1)函数签名:

		def zip[U: ClassTag](other: RDD[U]): RDD[(T, U)]

2)功能说明

该操作可以将两个RDD中的元素,以键值对的形式进行合并。其中,键值对中的Key为第

1个RDD中的元素,Value为第2个RDD中的元素。

将两个RDD组合成Key/Value形式的RDD,这里默认两个RDD的partition数量以及元素数

量都相同,否则会抛出异常。

3)需求说明:创建两个RDD,并将两个RDD组合到一起形成一个(k,v)RDD

4)代码实现

package com.xiao_after.doublevalue

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

/**
 * @author xiaohu
 * @create 2020-09-25 0:53
 */
object DoubleValue04_zip {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建第一个RDD
    val rdd1: RDD[Int] = sc.makeRDD(Array(1,2,3),3)

    //3.2 创建第二个RDD
    val rdd2: RDD[String] = sc.makeRDD(Array("a","b","c"),3)

    rdd1.zip(rdd2).collect().foreach(println)

    println("----------------------------")

    rdd2.zip(rdd1).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

(1,a)
(2,b)
(3,c)
----------------------------
(a,1)
(b,2)
(c,3)

3 Key-Value类型

1)com.xiao_after.keyvalue

3.1.1 partitionBy()按照K重新分区

1)函数签名:

		def partitionBy(partitioner: Partitioner): RDD[(K, V)]

2)功能说明

将RDD[K,V]中的K按照指定Partitioner重新进行分区;

如果原有的RDD和新的RDD是一致的话就不进行分区,否则会产生Shuffle过程。

3)需求说明:创建一个3个分区的RDD,对其重新分区

3.1.2 自定义分区

1)HashPartitioner源码解读

class HashPartitioner(partitions: Int) extends Partitioner {

    require(partitions >= 0, s"Number of partitions ($partitions) cannot be negative.")
    
    def numPartitions: Int = partitions
    
    def getPartition(key: Any): Int = key match {
        case null => 0
        case _ => Utils.nonNegativeMod(key.hashCode, numPartitions)
    }
    
    override def equals(other: Any): Boolean = other match {
        case h: HashPartitioner =>
            h.numPartitions == numPartitions
        case _ =>
            false
    }
    
    override def hashCode: Int = numPartitions
}

2)自定义分区器

要实现自定义分区器,需要继承org.apache.spark.Partitioner类,并实现下面三个方

法。

(1)numPartitions: Int:返回创建出来的分区数。

(2)getPartition(key: Any): Int:返回给定键的分区编号(0到numPartitions-1)。

(3)equals():Java 判断相等性的标准方法。这个方法的实现非常重要,Spark需要用这

个方法来检查你的分区器对象是否和其他分区器实例相同,这样Spark才可以判断两个

RDD的分区方式是否相同


4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:04
 */
object KeyValue01_partitionBy {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "aaa"), (2, "bbb"), (3, "ccc")), 3)

    //3.2 按照hash值来分组
    val rdd1: RDD[(Int, String)] = rdd.partitionBy(new HashPartitioner(2))

    //3.3 匹配组号并打印
    rdd1.mapPartitionsWithIndex {
      (indes, items) =>
        items.map((indes, _))
    }.collect().foreach(println)

    println("---------------------------")

    //3.4 按照自定义分区
    val rdd2: RDD[(Int, String)] = rdd.partitionBy(new myPartitioner(2))

    //3.5 匹配组号并打印
    rdd2.mapPartitionsWithIndex {
      (index, items) =>
        items.map((index, _))
    }.collect().foreach(println)


    //4.关闭连接
    sc.stop()

  }
}

//自定义分区:按照对2取模来分
class myPartitioner(num: Int) extends Partitioner {
  override def numPartitions: Int = num

  override def getPartition(key: Any): Int = {
    if (key.isInstanceOf[Int]) {
      val keyInt: Int = key.asInstanceOf[Int]
      if (keyInt % 2 == 0) 0 else 1
    } else 0
  }
}

5)运行结果

(0,(2,bbb))
(1,(1,aaa))
(1,(3,ccc))
---------------------------
(0,(2,bbb))
(1,(1,aaa))
(1,(3,ccc))
3.2 reduceByKey()按照K聚合V

1)函数签名:

def reduceByKey(func: (V, V) => V): RDD[(K, V)]
def reduceByKey(func: (V, V) => V, numPartitions: Int): RDD[(K, V)]

2)功能说明:该操作可以将RDD[K,V]中的元素按照相同的K对V进行聚合。其存在多种重

载形式,还可以设置新RDD的分区数。

3)需求说明:统计单词出现次数

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:05
 */
object KeyValue02_reduceByKey {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd = sc.makeRDD(List(("a", 1), ("b", 5), ("a", 5), ("b", 2)))

    //3.2 执行reduceByKey并循环遍历
    rdd.reduceByKey(_ + _).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

(a,6)
(b,7)
3.3 groupByKey()按照K重新分组

1)函数签名:

	def groupByKey(): RDD[(K, Iterable[V])]

2)功能说明

groupByKey对每个key进行操作,但只生成一个seq,并不进行聚合。

该操作可以指定分区器或者分区数(默认使用HashPartitioner)

3)需求说明:统计单词出现次数

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:05
 */
object KeyValue03_groupByKey {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd = sc.makeRDD(List(("a", 1), ("b", 5), ("a", 5), ("b", 2)))

    //3.2 执行groupByKey
    val rdd1: RDD[(String, Iterable[Int])] = rdd.groupByKey()

    //3.3 计算相同key对应值的相加结果
    rdd1.map(t => (t._1, t._2.sum)).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

(a,6)
(b,7)
3.4 reduceByKey和groupByKey区别

1)reduceByKey:按照key进行聚合,在shuffle之前有combine(预聚合)操作,返回

结果是RDD[K,V]。

2)groupByKey:按照key进行分组,直接进行shuffle。

3)开发指导:在不影响业务逻辑的前提下,优先选用reduceByKey。求和操作不影响业

务逻辑,求平均值影响业务逻辑。

3.5 aggregateByKey()按照K处理分区内和分区间逻辑

1)函数签名

  def aggregateByKey[U: ClassTag](zeroValue: U)(seqOp: (U, V) => U,
      combOp: (U, U) => U): RDD[(K, U)] 

①zeroValue(初始值):给每一个分区中的每一种key一个初始值;

②seqOp(分区内):函数用于在每一个分区中用初始值逐步迭代value;

③combOp(分区间):函数用于合并每个分区中的结果。

2)需求分析:取出每个分区间相同的 key 对应值的最大值,然后相加

3)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:05
 */
object KeyValue04_aggregateByKey {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("a", 3), ("a", 2), ("c", 4), ("b", 3), ("c", 6), ("c", 8)), 2)

    //3.2 取出每个分区相同key对应值的最大值,然后相加
    rdd.aggregateByKey(0)(math.max, _ + _).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

4)运行结果

(b,3)
(a,3)
(c,12)
3.6 foldByKey()分区内和分区间相同的aggregateByKey()

1)函数签名:

  def foldByKey(zeroValue: V)(func: (V, V) => V): RDD[(K, V)]

①参数zeroValue:是一个初始化值,它可以是任意类型;

②参数func:是一个函数,两个输入参数相同。

2)功能说明:aggregateByKey的简化操作,seqop和combop相同。即,分区内逻辑和

分区间逻辑相同。

3)需求说明:求wordCount

①创建一个RDD

②求wordCount

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:05
 */
object KeyValue05_foldByKey {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val list: List[(String, Int)] = List(("a", 1), ("a", 1), ("a", 1), ("b", 1), ("b", 1), ("b", 1), ("b", 1), ("a", 1))
    val rdd: RDD[(String, Int)] = sc.makeRDD(list, 2)

    //3.2 执行foldByKey
    rdd.foldByKey(0)(_ + _).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }

}

5)运行结果

(b,4)
(a,4)
3.7 combineByKey()转换结构后分区内和分区间操作

1)函数签名:

     def combineByKey[C](
     createCombiner: V => C,
     mergeValue: (C, V) => C,
     mergeCombiners: (C, C) => C): RDD[(K, C)]

(1)createCombiner(转换数据的结构): combineByKey() 会遍历分区中的所有元

素,因此每个元素的键要么还没有遇到过,要么就和之前的某个元素的键相同。如果这

是一个新的元素,combineByKey()会使用一个叫作createCombiner()的函数来创建那个

键对应的累加器的初始值

(2)mergeValue(分区内): 如果这是一个在处理当前分区之前已经遇到的键,它会使

用mergeValue()方法将该键的累加器对应的当前值与这个新的值进行合并

(3)mergeCombiners(分区间): 由于每个分区都是独立处理的,因此对于同一个键

可以有多个累加器。如果有两个或者更多的分区都有对应同一个键的累加器,就需要使

用用户提供的mergeCombiners()方法将各个分区的结果进行合并。

2)功能说明

针对相同K,将V合并成一个集合。

3)需求说明:创建一个pairRDD,根据key计算每种key的均值。(先计算每个key出现

的次数以及可以对应值的总和,再相除得到结果)

4)需求分析:针对一个pairRDD,计算每种key对应值的和,再根据key计算每种key的

均值。

5)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:05
 */
object KeyValue06_combineByKey {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val list: List[(String, Int)] = List(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98))
    val rdd: RDD[(String, Int)] = sc.makeRDD(list, 2)

    //3.2
    rdd.combineByKey(
      (_, 1),
      (acc: (Int, Int), v) => (acc._1 + v, acc._2 + 1),
      (acc1: (Int, Int), acc2: (Int, Int)) => (acc1._1 + acc2._1, acc1._2 + acc2._2)
    ).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }

}

6)运行结果

(b,4)
(a,4)
3.8 reduceByKey、foldByKey、aggregateByKey、combineByKey

reduceByKey:第一个初始值不变

foldByKey:分区内和分区间规则一致

aggregateByKey:第一个初始值和分区内处理规则一致

combineByKey:把第一个值变成特定的结构

3.9 sortByKey()按照K进行排序

1)函数签名:

      def sortByKey(
      ascending: Boolean = true, // 默认,升序
      numPartitions: Int = self.partitions.length)  : RDD[(K, V)]

2)功能说明

在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)

的RDD

3)需求说明:创建一个pairRDD,按照key的正序和倒序进行排序

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:06
 */
object KeyValue07_sortByKey {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((3,"aa"),(6,"cc"),(2,"bb"),(1,"dd")))

    //3.2 默认正序
    rdd.sortByKey().collect().foreach(println)

    println("-----------------------")

    //3.3 设置反序
    rdd.sortByKey(false).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }
}

5)运行结果

(1,dd)
(2,bb)
(3,aa)
(6,cc)
-----------------------
(6,cc)
(3,aa)
(2,bb)
(1,dd)
3.10 mapValues()只对V进行操作

1)函数签名:

def mapValues[U](f: V => U): RDD[(K, U)]

2)功能说明:针对于(K,V)形式的类型只对V进行操作

3)需求说明:创建一个pairRDD,并将value添加字符串"$"

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:06
 */
object KeyValue08_mapValues {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (1, "d"), (2, "b"), (3, "c")))

    //3.2
    rdd.mapValues(_ + "$").collect().foreach(println)


    //4.关闭连接
    sc.stop()

  }

}

5)运行结果

(1,a$)
(1,d$)
(2,b$)
(3,c$)
3.11 join()连接

1)函数签名:

def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
def join[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, W))] 

2)功能说明

在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,

(V,W))的RDD

3)需求说明:创建两个pairRDD,并将key相同的数据聚合到一个元组。

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:06
 */
object KeyValue09_join {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建第一个RDD
    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))

    //3.2 创建第二个pairRDD
    val rdd1: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
    rdd.join(rdd1).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }

}

5)运行结果

(1,(a,4))
(2,(b,5))
3.12 cogroup()类似全连接,但是在同一个RDD中对key聚合

1)函数签名:

def cogroup[W](other: RDD[(K, W)]): RDD[(K, (Iterable[V], Iterable[W]))]

2)功能说明

在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD

操作两个RDD中的KV元素,每个RDD中相同key中的元素分别聚合成一个集合。

3)需求说明:创建两个pairRDD,并将key相同的数据聚合到一个迭代器。

4)代码实现

package com.xiao_after.key_value

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

/**
 * @author xiaohu
 * @create 2020-09-25 1:06
 */
object KeyValue10_cogroup {
  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    //3.具体业务逻辑
    //3.1 创建一个RDD
    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c"), (4, "d")))

    //3.2 创建第二个RDD
    val rdd1: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (3, 6), (5, 6)))

    //3.3
    rdd.cogroup(rdd1).collect().foreach(println)

    //4.关闭连接
    sc.stop()

  }

}

5)运行结果

(1,(CompactBuffer(a),CompactBuffer(4)))
(2,(CompactBuffer(b),CompactBuffer(5)))
(3,(CompactBuffer(c),CompactBuffer(6)))
(4,(CompactBuffer(d),CompactBuffer()))
(5,(CompactBuffer(),CompactBuffer(6)))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值