spark-9.sparkcore_6_实例练习

现有一份CDN数据,该数据的格式为:

IP 命中率 响应时间 请求时间 请求方法 请求URL 请求协议 状态码 响应大小 referer 用户代理

一条样例数据如下:

100.79.121.48 HIT 33 [15/Feb/2017:00:00:46 +0800] "GET http://cdn.v.abc.com.cn/videojs/video.js HTTP/1.1" 200 174055 "http://www.abc.com.cn/" "Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+Trident/4.0;)"

处理需求:

  • 需求1:计算独立IP数
  • 需求2:统计每个视频独立IP数
  • 需求3:统计一天中每个小时的流量

scala代码如下:

package com.dengdan.spark

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

import scala.util.matching.Regex

/**
 * CDN流量统计
 */
object CdnStatics {
  /**
   * 日志对象,该程序中并未使用
   */
  val logger = LoggerFactory.getLogger(CdnStatics.getClass)
  /**
   * IP地址模式
   */
  val IPPattern = "((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d))))".r
  /**
   * 视频文件名模式
   */
  val videoPattern = "([0-9]+).mp4".r

  /**
   * [15/Feb/2017:11:17:13 +0800]  匹配 2017:11 按每小时播放量统计
   */
  val timePattern = ".*(2017):([0-9]{2}):[0-9]{2}:[0-9]{2}.*".r
  /**
   * 匹配http响应码和请求数据大小
   */
  val httpSizePattern = ".*\\s(200|206|304)\\s([0-9]+)\\s.*".r


  /**
   * 主方法
   *
   * @param args
   */
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setAppName("CdnStatics").setMaster("local[*]")
    val sc = new SparkContext(sparkConf)
    //读入文件到内存
    val data = sc.textFile("D:\\idea_workspace2020\\spark\\sparkcore\\sparkcore_cdn\\src\\main\\resources\\cdn.txt").cache()
    println("------------------------------------------------------")
    println(s"data的分区数 = ${data.partitions.size}") // 3
    println("------------------------------------------------------")
    //需求1:统计独立IP访问量TOP10
    println("---------------------需求1:统计独立IP访问量TOP10---------------------------------")
    ipStatics(data)
    //需求2:统计每个视频独立IP数
    println("---------------------需求2:统计每个视频独立IP数---------------------------------")
    videoIpStatics(data)
    //需求3:统计一天中每个小时间的流量
    println("----------------------需求3:统计一天中每个小时间的流量--------------------------------")
    flowOfHour(data)
    println("-------------------------------------------------------------------------------")
    sc.stop()
  }

  /**
   * 需求1 统计独立IP访问量TOP10
   *
   * @param data 输入RDD
   * @return
   */
  def ipStatics(data: RDD[String]): Unit = {
    //1.统计独立IP数
    val ipNums = data.map(x => (IPPattern.findFirstIn(x).get, 1)).reduceByKey(_ + _).sortBy(_._2, false)
    //2.输出IP访问量前10
    ipNums.take(10).foreach(println)
    //3.,打印独立IP数
    println("独立IP的个数:" + ipNums.count())
  }

  /**
   * 需求2:统计每个视频独立IP数
   *
   * @param data
   */
  def videoIpStatics(data: RDD[String]): Unit = {
    //获取文件名与IP的元组
    def getFileNameAndIp(line: String): (String, String) = {
      (videoPattern.findFirstIn(line).mkString, IPPattern.findFirstIn(line).mkString)
    }

    data.filter(x => x.matches(".*([0-9]+)\\.mp4.*")).map(x => getFileNameAndIp(x)).groupByKey().map(x => (x._1, x._2.toList.distinct))
      .sortBy(_._2.size, false).take(10).foreach(x => println("视频:" + x._1 + "独立IP数:" + x._2.size))
  }

  /**
   * 需求3:统计一天中每个小时间的流量
   *
   * @param data
   * @return
   */
  def flowOfHour(data: RDD[String]): Unit = {
    def isMatch(pattern: Regex, str: String): Boolean = {
      str match {
        case pattern(_*) => true
        case _ => false
      }
    }

    //获取日志中小时和http 请求体大小
    def getTimeAndSize(line: String) = {
      var res = ("", 0L)
      try {
        val httpSizePattern(code, size) = line
        val timePattern(year, hour) = line
        res = (hour, size.toLong)
      } catch {
        case ex: Exception => ex.printStackTrace()
      }
      res
    }

    //统计一天中每个小时的流量
    data.filter(x => isMatch(httpSizePattern, x)).filter(x => isMatch(timePattern, x)).map(x => getTimeAndSize(x)).groupByKey()
      .map(x => (x._1, x._2.sum)).sortByKey().foreach(x => println(x._1 + "时 CDN流量=" + x._2 / (1024 * 1024 * 1024) + "G"))
  }
}

运行结果:

------------------------------------------------------
data的分区数 = 3
------------------------------------------------------
---------------------需求1:统计独立IP访问量TOP10---------------------------------
(114.55.227.102,9348)
(220.191.255.197,2640)
(115.236.173.94,2476)
(183.129.221.102,2187)
(112.53.73.66,1794)
(115.236.173.95,1650)
(220.191.254.129,1278)
(218.88.25.200,751)
(183.129.221.104,569)
(115.236.173.93,529)
独立IP的个数:43649
---------------------需求2:统计每个视频独立IP数---------------------------------
视频:141081.mp4独立IP数:2393
视频:140995.mp4独立IP数:2050
视频:141027.mp4独立IP数:1784
视频:141090.mp4独立IP数:1702
视频:141032.mp4独立IP数:1528
视频:89973.mp4独立IP数:1523
视频:141080.mp4独立IP数:1425
视频:141035.mp4独立IP数:1321
视频:141082.mp4独立IP数:1272
视频:140938.mp4独立IP数:816
----------------------需求3:统计一天中每个小时间的流量--------------------------------
16时 CDN流量=45G
00时 CDN流量=14G
08时 CDN流量=43G
01时 CDN流量=3G
17时 CDN流量=44G
02时 CDN流量=5G
09时 CDN流量=52G
03时 CDN流量=3G
18时 CDN流量=45G
04时 CDN流量=3G
10时 CDN流量=61G
05时 CDN流量=4G
19时 CDN流量=51G
06时 CDN流量=11G
11时 CDN流量=45G
07时 CDN流量=22G
20时 CDN流量=55G
12时 CDN流量=46G
21时 CDN流量=53G
13时 CDN流量=51G
14时 CDN流量=55G
15时 CDN流量=45G
22时 CDN流量=42G
23时 CDN流量=25G
-------------------------------------------------------------------------------

Process finished with exit code 0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章