Spark自定义分区器(二)

本文介绍使用Apache Spark处理大规模数据集时,如何通过自定义分区器优化数据处理流程。具体展示了如何创建自定义分区器MyPartitioner,该分区器根据特定规则将数据分配到不同的分区,以提高reduceByKey操作的效率。文章详细解释了自定义分区器的实现原理,包括规则定义、分区数量确定及分区计算方法。

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

代码:

import java.net.URL

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

import scala.collection.mutable

object MostJobPartitioner {
  def main(args: Array[String]): Unit = {
//    val topN = args(1).toInt
    val topN = 3

    val conf = new SparkConf().setAppName("MostJobPartitioner").setMaster("local[4]")
    val sc = new SparkContext(conf)

    //指定以后从哪里读取数据
    val lines: RDD[String] = sc.textFile("C:\\Users\\S\\Desktop\\内民大实训\\person.log")
    //整理数据
    val jobPersonAndOn: RDD[((String, String), Int)] = lines.map(line => {
      val index = line.lastIndexOf("/")
      val person = line.substring(index + 1)
      val httpHost = line.substring(0, index)
      val job = new URL(httpHost).getHost.split("[.]")(0)
      ((job, person), 1)
    })


    //计算有多少学科  ((job,person),1)
    //jobs()
    val jobs: Array[String] = jobPersonAndOn.map(_._1._1).distinct().collect()

    //自定义一个分区器,并且按照指定的分区器进行分区
    val sbPatitioner = new MyPartitioner(jobs)

    //聚合,聚合是就按照指定的分区器进行分区
    //该RDD一个分区内仅有一个学科的数据
    val reduced: RDD[((String, String), Int)] = jobPersonAndOn.reduceByKey(sbPatitioner, _+_)

    //一次拿出一个分区(可以操作一个分区中的数据了)
    val sorted: RDD[((String, String), Int)] = reduced.mapPartitions(it => {
      //将迭代器转换成list,然后排序,在转换成迭代器返回
      //((job,person),3)
      it.toList.sortBy(_._2).reverse.take(topN).iterator

      //即排序,有不全部加载到内存

      //长度为3的一个可以排序的集合

    })

    //收集结果
    val r: Array[((String, String), Int)] = sorted.collect()
    println(r.toBuffer)

//    sorted.saveAsTextFile("C:\\Users\\S\\Desktop\\内民大实训\\log.log")


    sc.stop()
  }

}

//自定义分区器  javaee  php bigdata
class MyPartitioner(jobs: Array[String]) extends Partitioner {

  print("....." + jobs.toBuffer)
  //相当于主构造器(new的时候回执行一次)
  //用于存放规则的一个map
  val rules = new mutable.HashMap[String, Int]()
  var i = 0
  for(job <- jobs) {
    //rules(sb) = i
    rules.put(job, i)//rules : (javaee,0) (php,1) (bigdata,2)
    i += 1
  }

//  private val i: Int = rules("javaee")

  //返回分区的数量(下一个RDD有多少分区)
  override def numPartitions: Int = jobs.length

  //根据传入的key计算分区标号
  //key是一个元组(String, String)
  override def getPartition(key: Any): Int = {

    print("....key" + key.toString)
    //获取学科名称   (job,person)
    val job = key.asInstanceOf[(String, String)]._1

    //根据规则计算分区编号
    rules(job)   //0,1,2
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值