代码:
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
}
}