1. 定义
/*
* 1. 定义
* //使用 hasPartitioner ; 分区个数使用 父RDD分区个数
* def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
* //使用 HashPartitioner; 指定分区个数
* def groupBy[K](f: T => K,numPartitions: Int)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
* //使用自定义分区
* def groupBy[K](f: T => K, p: Partitioner)(implicit kt: ClassTag[K], ord: Ordering[K] = null): RDD[(K, Iterable[T])]
*
* 2. 功能
* 1. 按照传入的的规则(f: T => K),对元素进行分组,每个组包含一个key,和一个元素序列(K, Iterable[T])
* ,在根据key进行分区,最终生成 ShuffledRDD
*
* 3. note
* 1. 这个算子操作代价是非常大的(map端不会合并数据,肯能造成内存溢出)
* 2. 如果分组的目的是为了做 聚合操作,那么可以使用 reduceByKey、aggregateByKey 效率会高很多(map端会合并)
* */
/* groupBy 算子 */
object RddTransitionOperator_groupBy extends App {
private val sc: SparkContext = CommonUtils.getSparkContext("groupBy operator")
private val rdd: RDD[Long] = sc.range(1, 11, 1, 2)
//1.使用 hasPartitioner ; 分区个数使用 父RDD分区个数
private val rdd1: RDD[(Int, Iterable[Long])] = rdd.groupBy(
e =>
e % 3 match {
case 0 => 0
case 1 => 1
case 2 => 3
}
)
println(s"rdd类型:${rdd.getClass.getName}")
println(s"rdd1类型:${rdd1.getClass.getName}")
println(s"rdd分区个数:${rdd.getNumPartitions}")
println(s"rdd1分区个数:${rdd1.getNumPartitions}")
// rdd类型:org.apache.spark.rdd.MapPartitionsRDD
// rdd1类型:org.apache.spark.rdd.ShuffledRDD
// rdd分区个数:2
// rdd1分区个数:2
rdd1.collect().foreach(println(_))
// (0,CompactBuffer(3, 6, 9))
// (1,CompactBuffer(1, 4, 7, 10))
// (3,CompactBuffer(2, 5, 8))
//2.使用 HashPartitioner; 指定分区个数
private val rdd2: RDD[(Int, Iterable[Long])] = rdd.groupBy(
(e: Long) => {
e % 3 match {
case 0 => 0
case 1 => 1
case 2 => 2
}
}
, 3
)
println(s"rdd2类型:${rdd2.getClass.getName}")
println(s"rdd2分区个数:${rdd2.getNumPartitions}")
// rdd2类型:org.apache.spark.rdd.ShuffledRDD
// rdd2分区个数:3
rdd2.collect().foreach(println(_))
// (0,CompactBuffer(3, 6, 9))
// (1,CompactBuffer(1, 4, 7, 10))
// (2,CompactBuffer(2, 5, 8))
//3.使用自定义分区
private val rdd3: RDD[(Int, Iterable[Long])] = rdd.groupBy(
(e: Long) => {
e % 3 match {
case 0 => 0
case 1 => 1
case 2 => 2
}
}
, CustomPartitioner(6)
)
println(s"rdd3类型:${rdd3.getClass.getName}")
println(s"rdd3分区个数:${rdd3.getNumPartitions}")
// rdd3类型:org.apache.spark.rdd.ShuffledRDD
// rdd3分区个数:6
rdd3.collect().foreach(println(_))
// (0,CompactBuffer(3, 6, 9))
// (1,CompactBuffer(1, 4, 7, 10))
// (2,CompactBuffer(2, 5, 8))
rdd3.saveAsTextFile("src/main/data/output/listrdd5")
sc.stop()
//while (true) {}
}
/* 自定义分区器 */
case class CustomPartitioner(partitions: Int) extends Partitioner {
override def numPartitions: Int = partitions
override def getPartition(key: Any): Int = {
//根据 1、2、3、4分区
println(s"分区器中的key:${key.asInstanceOf[Int]}")
key.asInstanceOf[Int] match {
case 0 => 0
case 1 => 1
case 2 => 2
case 3 => 3
case 4 => 4
case _ => 5
}
}
}
需求1 : 将 List("Hello", "hive", "hbase", "Hadoop")根据单词首写字母进行分组
object groupByTest1 extends App {
val sparkconf: SparkConf = new SparkConf().setMaster("local").setAppName("groupByTest")
val sc: SparkContext = new SparkContext(sparkconf)
val rdd = sc.makeRDD(List("Hello", "hive", "hbase", "Hadoop"), 2)
var rdd1: RDD[(String, Iterable[String])] = rdd.groupBy(
_.substring(0, 1)
)
println(rdd1.collect().mkString(","))
sc.stop()
/*
* 执行结果
* (负数,CompactBuffer(-2, -10, -100)),(正数,CompactBuffer(1, 3, 14, 1))
*
* */
}
需求2 : 从服务器日志数据apache.log中获取每个时间段访问量(按小时统计)
object groupByTest2 extends App {
val sparkconf: SparkConf = new SparkConf().setMaster("local").setAppName("groupByTest")
val sc: SparkContext = new SparkContext(sparkconf)
val rdd = sc.textFile("Spark_319/src/data/input/apache.log")
//从日志行中 获取小时
private val rdd1: RDD[String] = rdd.map(_.split(" ")(3).split(":")(1))
//对小时分组
private val rdd2: RDD[(String, Iterable[String])] = rdd1.groupBy(
e => e
)
//对小时分组内求和
private val rdd3: RDD[(String, Int)] = rdd2.map(
tp => (tp._1, tp._2.size)
)
println(rdd3.collect().mkString(","))
sc.stop()
/*
* 执行结果
* (14,498),(21,453),(06,366),(20,486),(19,493)...
*
* */
}
需求3 : WordCount
object groupByTest3 extends App {
val sparkconf: SparkConf = new SparkConf().setMaster("local").setAppName("groupByTest")
val sc: SparkContext = new SparkContext(sparkconf)
//读取文件
val rdd = sc.textFile("Spark_319/src/data/*.txt")
//拆分单词
private val rdd1: RDD[String] = rdd.flatMap(_.split(" "))
//对单词分组
private val rdd2: RDD[(String, Iterable[String])] = rdd1.groupBy(e => e)
//对分组统计
private val rdd3: RDD[(String, Int)] = rdd2.map(tp => (tp._1, tp._2.size))
rdd3.collect().foreach(println(_))
sc.stop()
/*
* 执行结果
* (曹操,6)
(关羽,3)
(张飞,3)
(孙权,3)
(刘备,3)
(政党,3)
(政府,3)
*
* */
}