數據結構小白的第一次嘗試------queue (項目實戰)

項目中有一個需求,求取taxi出行od的最大峯值(taxi od最大交叉值),採用隊列處理:
需求示意圖如下:
在這裏插入圖片描述
案例(自制測試數據):
val data = Seq(
(“A”,“2019-01-05 00:23:20”,“2019-01-05 00:27:20”,“2019-1-05”),
(“A”,“2019-01-05 00:25:20”,“2019-01-05 00:37:20”,“2019-1-05”),
(“A”,“2019-01-05 00:35:20”,“2019-01-05 00:40:20”,“2019-1-05”),
(“A”,“2019-01-05 01:25:20”,“2019-01-05 01:37:20”,“2019-1-05”),
(“A”,“2019-01-05 02:25:20”,“2019-01-05 02:37:20”,“2019-1-05”),
(“A”,“2019-01-05 02:26:20”,“2019-01-05 02:30:20”,“2019-1-05”),
(“A”,“2019-01-05 02:27:20”,“2019-01-05 02:28:20”,“2019-1-05”),
(“A”,“2019-01-05 02:27:40”,“2019-01-05 03:37:20”,“2019-1-05”),
(“A”,“2019-01-05 04:25:20”,“2019-01-05 04:57:20”,“2019-1-05”),
(“A”,“2019-01-05 04:35:20”,“2019-01-05 05:37:20”,“2019-1-05”),
(“A”,“2019-01-05 05:00:20”,“2019-01-05 06:37:20”,“2019-1-05”),
(“A”,“2019-01-05 08:25:20”,“2019-01-05 08:37:20”,“2019-1-05”),
(“A”,“2019-01-05 09:25:20”,“2019-01-05 09:37:20”,“2019-1-05”),
(“A”,“2019-01-05 09:35:20”,“2019-01-05 09:47:20”,“2019-1-05”),
(“A”,“2019-01-05 10:35:20”,“2019-01-05 10:47:20”,“2019-1-05”)
).toDF(“carID”,“departTime”,“arrivalTime”,“date”)

  /**
    * 提取大OD
    */
  def getBigOD(data: DataFrame): DataFrame = {
    import data.sparkSession.implicits._
    data.groupByKey(row => row.getAs[String]("carID") + "," + row.getAs[String]("date")).flatMapGroups((str, it) => {
      val indexArr = ArrayBuffer[(Int, Int, String)]() //標記大od劃分時對應的records記錄下標、最大od數、大od的結束時間
      val res = ArrayBuffer[(String, String, Int, String)]()
      val info = str.split(",")
      val carID = info.head
      val date = info.last
      val records = it.toList.sortBy(_.getAs[String]("arrivalTime"))
      val queue = new Queue[Row]()
      val len_records = records.length
      //當天記錄數在2條及以上
      if (len_records >= 2) {
        var maxOdNum = 0 //初始化od數量
        var index = 0 //初始化標記
        var lastTime = "" //大od結束時的時間
        for (record <- records) {
          //首條記錄入隊
          if (queue.length == 0) {
            queue.enqueue(record)
          } else {
            //判斷當前od是否應該加入隊列
            val departTime = record.getAs[String]("departTime")
            //遍歷隊列中的所有od
            var flag = true
            var bg = 0
            while (bg < queue.length && flag) {
              val que = queue(bg)
              val arrivalTime = que.getAs[String]("arrivalTime")
              // 當前od的上車時間若大於隊列中od的到達時間,則隊列中已存od出隊
              if (departTime > arrivalTime) {
                val queueLen = queue.length
                if (queueLen > maxOdNum) maxOdNum = queueLen //隊首元素出列前,隊列的最大長度賦值給maxOdNum
                queue.dequeue() //隊首元素出列
                bg -= 1 //隊首元素出列後,下一次依舊從隊首元素開始判斷(**易忽略**)
              } else {
                queue.enqueue(record)
                flag = false //當前上車時間小於隊首元素的下車時間,則不必再往後查看,直接加入當前od即可
              }
              bg += 1
            }
            flag = true //供下一次循環隊列使用

            //若隊列清空,則表示一次大od劃分成功
            if (queue.length == 0) {
              // 出棧元素應該添加至最終的結果集中
              lastTime = records(index-1).getAs[String]("arrivalTime")
              indexArr.append((index-1, maxOdNum, lastTime))
              //清空列表後,需將當前od加入隊列中,成爲隊首元素
              queue.enqueue(record)
              maxOdNum = 0 //maxOdNum值歸零
            }
          }

          //插入最後一個元素後,需輸出一次
          if (index == len_records - 1) {
            lastTime = records.last.getAs[String]("arrivalTime")
            indexArr.append((index, queue.length, lastTime))
          }
          index += 1
        }
      } else {
        //只有一條記錄,直接添加進去即可
        val lastTime = records.last.getAs[String]("arrivalTime")
        indexArr.append((0, 1, lastTime))
      }

      for (ind <- indexArr) {
        res.append((carID, date, ind._2, ind._3))
      }
      //根據indexArr和records生成最終的結果數據集
      res
    }).toDF("carID", "date", "maxOdNum", "endTime")
  }

在這裏插入圖片描述result:
在這裏插入圖片描述

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