Spark - 小實踐(6)計算手機在基站停留時間

背景

         原文轉自作者Allen-Gao的一位博主,使用的api是RDD計算,文章最後附上我的和原博主的代碼。

         項目說明:附件爲要計算數據的demo。附件(https://download.csdn.net/download/u013560925/10425558)

         

          其中bs_log文件夾數據格式爲(手機號,時間戳,基站ID,連接狀態(“1”爲連接,“0”爲斷開))

          lac_info.txt 文件數據格式爲(基站ID,經度,緯度,信號輻射類型)

          程序思路:

1、先根據"手機號,基站ID"構成一個元祖,做爲唯一標識, 和時間戳構成新的數據結構->(手機號, 站點, 時間戳)

2、(手機號,基站ID)作爲key,通過reduceByKey算子進行聚合,計算出在基站的停留時間,構成新的數據結構,以便和座標數據進行joi

n,->(基站ID,(手機號,停留時間))

3、將基站座標數據信息通過map,構建成數據類型 ->(基站ID,(經度,緯度))

4、將2、3進行join操作,構成新的數據類型 ->(手機號,基站ID,停留時間,經度,緯度)

5、按手機號進行分組。->(手機號,(手機號,基站ID,停留時間,經度,緯度))

6、取出停留時間最長的兩個基站ID。

正文

         原作者提供了兩個數據集,手機在某個基站的狀態和基站的位置信息:

         原作者思路:先join,後篩選出手機停留基站時間top數據

         我的代碼實現:先篩選出手機停留基站時間top數據,然後跟基站位置信息join

原作者代碼:

[plain] view plain copy
  1. package cn.allengao.Location  
  2.   
  3. import org.apache.spark.{SparkConf, SparkContext}  
  4.   
  5. /**  
  6.   * class_name:  
  7.   * package:  
  8.   * describe: 基站信息查詢  
  9.   * creat_user: Allen Gao  
  10.   * creat_date: 2018/1/29  
  11.   * creat_time: 10:03  
  12.   **/  
  13.   
  14. /*  
  15.   *   說明:  
  16.   *   1, 先根據"手機號,基站ID"構成一個元祖,做爲唯一標識, 和時間戳構成新的數據結構->(手機號, 站點, 時間戳)  
  17.   *   2、(手機號,基站ID)作爲key,通過reduceByKey算子進行聚合,計算出在基站的停留時間,構成新的數據結構,  
  18.   *   以便和座標數據進行join,->(基站ID,(手機號,停留時間))  
  19.   *   3、將基站座標數據信息通過map,構建成數據類型 ->(基站ID,(經度,緯度))  
  20.   *   4、將2、3進行join操作,構成新的數據類型 ->(手機號,基站ID,停留時間,經度,緯度)  
  21.   *   5、按手機號進行分組。->(手機號,(手機號,基站ID,停留時間,經度,緯度))  
  22.   *   6、取出停留時間最長的兩個基站ID。  
  23.   *  
  24.  */  
  25. object UserLocation {  
  26.   def main(args: Array[String]): Unit = {  
  27.     //創建Spark配置信息  
  28.     val conf = new SparkConf().setAppName("UserLocation").setMaster("local[*]")  
  29.     //建立Spark上下文,並將配置信息導入  
  30.     val sc = new SparkContext(conf)  
  31.     /*  
  32.     基站連接手機號,連接時間戳,基站站點ID信息,“1”表示連接,“0”表示斷開連接。  
  33.     18688888888,20160327082400,16030401EAFB68F1E3CDF819735E1C66,1  
  34.      */  
  35.     //從log文件拿到數據,並按行採集。  
  36.     //sc.textFile("c://information//bs_log").map(_.split(",")).map(x => (x(0), x(1), x(2), x(3)))  
  37.     val rdd_Info = sc.textFile("j://information//bs_log").map(line => {  
  38.       //通過“,”將數據進行切分field(0)手機號,field(1)時間戳,field(2)基站ID信息,field(3)事件類型  
  39.       val fields = line.split(",")  
  40.       //事件類型,“1”表示連接,“0”表示斷開。  
  41.       val eventType = fields(3)  
  42.       val time = fields(1)  
  43.       //連接基站將時間戳至爲“-”,斷開基站將時間戳至爲“+”,以便後面進行計算。  
  44.       val timeLong = if(eventType == "1") -time.toLong else time.toLong  
  45.       //構成一個數據類型(手機號,基站ID信息,帶符號的時間戳)  
  46.       ((fields(0),fields(2)),timeLong)  
  47.     })  
  48.     val rdd_lacInfo = rdd_Info.reduceByKey(_+_).map(t=>{  
  49.       val mobile = t._1._1  
  50.       val lac = t._1._2  
  51.       val time = t._2  
  52.       (lac, (mobile, time))  
  53.     })  
  54.     val rdd_coordinate = sc.textFile("j://information//lac_info.txt").map(line =>{  
  55.       val f = line.split(",")  
  56.       //(基站ID, (經度, 緯度))  
  57.       (f(0),(f(1), f(2)))  
  58.     })  
  59.     //rdd1.join(rdd2)-->(CC0710CC94ECC657A8561DE549D940E0,((18688888888,1300),(116.303955,40.041935)))  
  60.     val rdd_all = rdd_lacInfo.join(rdd_coordinate).map(t =>{  
  61.       val lac = t._1  
  62.       val mobile = t._2._1._1  
  63.       val time = t._2._1._2  
  64.       val x = t._2._2._1  
  65.       val y = t._2._2._2  
  66.       (mobile, lac, time, x, y)  
  67.     })  
  68.     //按照手機號進行分組  
  69.     val rdd_mobile = rdd_all.groupBy(_._1)  
  70.     //取出停留時間最長的前兩個基站  
  71.     val rdd_topTwo= rdd_mobile.mapValues(it =>{  
  72.       it.toList.sortBy(_._3).reverse.take(2)  
  73.     })  
  74.   
  75. //    println(rdd_Info.collect().toBuffer)  
  76. //    println(rdd_lacInfo.collect().toBuffer)  
  77. //    println(rdd_coordinate.collect().toBuffer)  
  78. //    println(rdd_all.collect().toBuffer)  
  79. //    println(rdd_mobile.collect().toBuffer)  
  80. //    println(rdd_topTwo.collect().toBuffer)  
  81.     rdd_topTwo.saveAsTextFile("j://information//out")  
  82.     sc.stop()  
  83.   }  
  84.   
  85. }  

我的代碼:

val data = spark.read.textFile("hdfs://master:9000/user/wangqi/logs").rdd
      .map(x=>x.split(",")).map(line=>{
      val stayTime = if(line(3).toInt==1) line(1).toLong else  -line(1).toLong
      ((line(0),line(2)),stayTime)
    }).reduceByKey(_+_).groupBy(_._1._2).mapValues(it=>{
      it.toList.sortBy(_._2).reverse.take(2)
    }).flatMap{
      line=>line._2
    }

    val top2Rdd = data.map(line=>(line._1._2,(line._1._1,line._2)))

    val lacRdd = spark.read.textFile("hdfs://master:9000/user/wangqi/lac_info.txt").rdd
      .map(line=>{
        val f = line.split(",")
        (f(0),(f(1),f(2)))
      })
    val result = lacRdd.join(top2Rdd).map(line=>(line._2._2._1,line._1,line._2._2._2,line._2._1._1,line._2._1._2))
    result.saveAsTextFile("hdfs://master:9000/user/wangqi/lacResult")

總結

         sortBy(key,false)按照key進行降序排列

         groupBy:後是(key,List())後可使用mapValues對List進行操作

         核心思想是:尋找所有類別格子的top數據

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