spark中自定义分区排序(解决数据倾斜问题)

美图欣赏:
spark中自定义分区排序(解决数据倾斜问题)_第1张图片
一.背景

我们都知道Spark内部提供了HashPartitionerRangePartitioner两种分区策略,这两种分区策略在很多情况下都适合我们的场景。但是有些情况下,Spark内部不能符合咱们的需求,这时候我们就可以自定义分区策略(注:默认是HashPartitioner分区)

二.如何实现

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

numPartitions: Int:返回创建出来的分区数

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

三.数据模板

这里,主要是为了测试自定义分区。数据量相对不是特别大

里面一共有五门课程:ui ,java , h5 , bigdata , android

spark中自定义分区排序(解决数据倾斜问题)_第2张图片

四.需求

自定分区,数据中有不同的学科,将输出的一个学科生成一个文件。

思路,从需求进行分析,然后通过不同算子进行转换。

五.代码实现

import java.net.URL

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

import scala.collection.mutable

/**
  * 自定义分区器实现自己的分区逻辑
  */
object CustomPartitioner_2 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName(this.getClass.getName).setMaster("local[2]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("ERROR")

    // 获取数据并切分生成元组
    val tups = sc.textFile("D:\\scala学习笔记\\day10\\datasource")
      .map(line => (line.split("\t")(1), 1))

    println(tups.collect.toBuffer)
    // 聚合生成各个模块的访问量
    val aggred: RDD[(String, Int)] = tups.reduceByKey(_ + _).cache()
    println(aggred.collect.toBuffer)

    // 获取学科信息并返回学科信息及url和访问量
    val subjectAndUrlAndCount: RDD[(String, (String, Int))] = aggred.map(tup => {
      val url = tup._1
      val count = tup._2
      val subject = new URL(url).getHost
      (subject, (url, count))
    }).cache()
    println(subjectAndUrlAndCount.collect.toBuffer)


    //    调用默认的分区器查看分区情况(HashPartitioner)
    //    val partitioned: RDD[(String, (String, Int))] = subjectAndUrlAndCount.partitionBy(new HashPartitioner(5))
    //    partitioned.saveAsTextFile("D:\\scala学习笔记\\day101\\")

    //获取到所有的学科信息
    val subjects: RDD[String] = subjectAndUrlAndCount.keys.distinct
    val subjectArr: Array[String] = subjects.collect()

    //调用自定义分区器进行分区
    val partition: RDD[(String, (String, Int))] = subjectAndUrlAndCount.partitionBy(new SubjectPartioner(subjectArr))

    //分组排序并取top3
    val result: RDD[(String, (String, Int))] = partition.mapPartitions(it => {
      it.toList.sortWith(_._2._2 > _._2._2).take(3).iterator
    })
    result.saveAsTextFile("D:\\scala学习笔记\\day11")

  }
}

/**
  * 自定义分区器
  */
class SubjectPartioner(subjectArr: Array[String]) extends Partitioner {
  //获取分区数
  override def numPartitions: Int = subjectArr.length

  //获取分区号
  override def getPartition(key: Any): Int = {
    val subjectAndNum = new mutable.HashMap[String, Int]()

    //计数器
    var i = 0
    for (subject <- subjectArr) {
      subjectAndNum += (subject -> i)
      i += 1
    }
    subjectAndNum.getOrElse(key.toString, 0)
  }
}

最终结果:

spark中自定义分区排序(解决数据倾斜问题)_第3张图片
拿出来其中一个分区数据看看:

最终统计出来了,前三 (符合需求)

在这里插入图片描述

            ————保持饥饿,保持学习
                   Jackson_MVP

你可能感兴趣的:(Spark)