Spark学生上网分析(清洗,上网情况分析,用网情况分析)

一、

1.需求:

(1).数据清洗
    1)读取sexDictFile.csv文件,把读出的数据封装成性别Map
    2)spark读取netClean.csv文件,写一个过滤脏数据的方法,用filter算子过滤掉。
    3)把性别加入源文件的第二个字段,返回字符串或tuple。
    4)把返回值写入文件

(2).上网情况分析
    1)读取刚才清洗过的文件
    2)读出里面的字段,新加24个字段并赋予默认值0.
    3)把开始上网时间和结束上网时间格式化成Date格式。
    4)计算上网时间(日期为同一天,在线时间各个小时加1;日期不在一天,开始时间到23点和0到结束时间内的各个小时加1)
    5)算出统计的年月(开始时间格式化成yyyy-MM-01)
    6)通过入学年份,上网时间的年,月计算学期
        (上网年份-入学年份)*2
        如果月份>6 学期再加1
    7)返回(userId+"#"+onlineYearMonth+"#"+semester -> hourOnlineCounts.toList)
    8)reduceByKey(24小时的值纵向相加)
    9)把处理后的数据分解为要写入文件的形式
    10)写入文件

(3).用网情况分析
    1)读取刚才清洗过的文件
    2)生成学号,性别,熬夜次数,上网时长,上网年月,学期 字段
        熬夜次数:如果跨夜或者没跨夜但是23:30后下网的 熬夜次数加1
        上网时长:(结束时间-开始时间)/3600000
    3)map算子返回所有字段(把熬夜次数和上网时长展开),用reduceByKey纵向求和
    4)通过map算子分别算出最大熬夜次数,最小熬夜次数,最大上网时间,最小上网时间
    5)通过上一步得出的值计算上网程度
        通过最大值和最小值计算能力值(熬夜次数和上网时长公用同一个公式)
        公式:(每条数据的值-该数据的最小值)/(该数据最大值-该数据最小值)
        程度=能力值*权重
    6)返回userId+","+sex+","+onlineYearMonth+","+semester+","+userNetDegree
    7)写入文件。

2.相关数据源:

百度网盘链接: https://pan.baidu.com/s/12EBaf1E2fqatcQ57SxuFyQ?pwd=d2b6 提取码: d2b6 

二、

1.ETL数据清洗

package Server

import org.apache.spark.{SparkConf, SparkContext}

import java.text.SimpleDateFormat
import java.util.Date
import scala.io.Source
import scala.util.{Failure, Success}

/** ****************************************
 *
 * @ClassName CleanData
 * @Description 清洗数据的类
 * @Author sanglong
 * @Date 2022/7/22 14:36
 * @Version 1.8
 *          *************************************** */
object CleanData {

  //定义输入文件的路径,以及清洗完成后的输出路径
  val sexFilePath = "G:\\datas\\input\\sexDictFile.csv"
  val netFilePath = "G:\\datas\\input\\netClean.csv"
  val resOutFilePath = "G:\\datas\\output\\cleanData.csv"

  //把性别封装为一个Map,key为学号,value为对应的性别
  //2015011203,2
  //2015011106,1
  //2015011205,1 表格中的数据实例
  def getSexMap = {
    //获得对应路径下的文本内容,sex表
    val content = Source.fromFile(sexFilePath)
    //获得表的每一行的数据
    val rowList = content.getLines().toList
    //定义一个可变的Map集合,用于存储性别键值对
    val sexMapBuff = Map[String, String]().toBuffer

    //对一行数据进行处理的方法
    def process(row: String) = {
      //拆分后的内容
      val line = row.split(",")
      //学号
      val stuId = line(0)
      //性别
      val sex = line(1)
      //映射后加入Map中,学号->性别
      sexMapBuff.append((stuId, sex))
    }

    //遍历,对每一行数据进行处理
    rowList.foreach(process)

    //释放资源
    content.close()

    //将可变的Map还转为不可变的
    sexMapBuff.toMap
  }

  //这个方法用于给定清洗条件,过滤脏数据
  //过滤条件:
  //1.每个字段不能为空
  //2.下机时间必须大于上机时间
  //3.表头行需要特殊处理
  //4.时间要符合现实规范
  def filterDirtyData(line: String): Boolean = {
    //作为返回值,先定义
    var boo = true
    //表头需要先判断
    // userId,startTime,endTime
    if (!line.contains("stuId") && !line.contains("startTime") && !line.contains("endTime")) {
      //对表数据的每一行内容进行拆分
      //实例数据如下:
      //2015011230,2015/10/21 11:44,2015/10/21 17:11
      //2015011203,2015/10/9 15:38,2015/10/9 16:37
      val linecontent = line.split(",")
      //判空,以及判断拆分后是否符合所需
      if (linecontent.size == 3) {
        //判断每个字段是否为空
        linecontent.foreach((field: String) => {
          if (null == field || field.equals("")) {
            println(line + "字段存在空值")
            //返回值
            boo = false
          }
        })
      } else {
        println(line + "改行格式存在问题")
        boo = false
      }
      //上面全部满足才会继续判断
      if (boo) {
        // 即上机时间,下机时间,以及时间的规范
        //2015011230,2015/10/21 11:44,2015/10/21 17:11
        //上机时间
        val startTime = linecontent(1)
        val endTime = linecontent(2)
        //将字符串形式的数据转为Date类型的数据
        //要与你的数据格式对应
        val timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")
        //如果不符合格式,那么直接捕获异常
        val startTimeDate = util.Try(timeFormat.parse(startTime))
        val endTimeDate = util.Try(timeFormat.parse(endTime))
        //捕获到异常,说明失败了
        val start = startTimeDate match {
          case Success(value) => value
          case Failure(exception) => {
            println(line + "日期格式存在问题")
            println("startTime==>" + exception)
            boo = false
          }
        }
        val end = endTimeDate match {
          case Success(value) => value
          case Failure(exception) => {
            println(line + "日期格式存在问题")
            println("endTime==>" + exception)
            boo = false
          }
        }

        //判断上下机时间是否符合现实,如果不是日期类的格式说明又问题
        if (start.getClass == classOf[Date]
          && end.getClass == classOf[Date]
          && start.asInstanceOf[Date].after(end.asInstanceOf[Date])) {
          println("上机时间晚于下机时间==>" + line)
          boo = false
        }
      }

    } else {
      println("表头行" + line)
      boo = false
    }
    boo
  }

  //清洗数据,接受来自于spark上下文对象的输入流
  def cleanDirtyData(sc: SparkContext) = {
    //获得性别与学号对应的键值对
    val sexMap = getSexMap
    //将过滤后的数据写入到指定路径下
    sc.textFile(netFilePath)
      .filter(filterDirtyData)
      .map((line: String) => {
        //对过滤后的数据进行拆分
        val netInfo = line.split(",")
        //获得对应的字段内容
        val stuId = netInfo(0)
        val startTime = netInfo(1)
        val endTime = netInfo(2)
        //通过Map集合获得学号对应的性别
        val sex = sexMap(stuId)
        //对所有的内容进行拼接,返回
        s"${stuId},${sex},${startTime},${endTime}"
      }).saveAsTextFile(resOutFilePath)
  }


  def main(args: Array[String]): Unit = {
    //为local【1】,可以让数据都分到一起,AppName只是名,随意
    val conf = new SparkConf().setMaster("local[1]").setAppName("cleanData")
    val sc = new SparkContext(conf)
    cleanDirtyData(sc)
  }

}

2.上网情况分析

package Server

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

import java.text.SimpleDateFormat
import scala.collection.mutable.ListBuffer
import scala.io.Source

/** ****************************************
 *
 * @ClassName Online
 * @Description 上网情况分析
 * @Author sanglong
 * @Date 2022/7/22 16:29
 * @Version 1.8
 *          *************************************** */

object Online {
  //定义输入文件的路径,以及分析完成后的输出路径
  val fileInputPath = "G:\\datas\\output\\cleanData\\cleanData.csv"
  val fileOutputPath = "G:\\datas\\output\\processData"
  //在类的级别上定义一个可变的List用于下面的数据读取
  val dataListBuffer = new ListBuffer[String]
  //最终处理完数据的list集合
  val resultListBuffer = new ListBuffer[String]

  //插入24列时间列,方便后面的分析
  def insertTimeFields: List[String] = {
    //获得对应路径下的文本内容,清洗后的表
    val content = Source.fromFile(fileInputPath)
    //获得表的每一行的数据
    val rowList = content.getLines().toList.toBuffer
    val resultList = new ListBuffer[String]

    //2015011123,2,2015/10/23 17:42,2015/10/23 23:36
    //清洗后的数据实例
    //增加24个字段并赋予默认值0
    def insertprocess(line: String): Unit = {
      val tempList = new ListBuffer[String]
      tempList.append(line)
      for (i <- 0 to 23) {
        tempList.append(",0")
      }
      resultList.append(tempList.toList.mkString)
    }

    rowList.foreach(insertprocess)
    //关闭资源
    content.close()
    //把可变转为不可变,
    rowList.toList
    // 并返回
    resultList.toList
  }

  //再次对每一行数据进行处理
  def againprocess(dataList: List[String], sc: SparkContext): RDD[(String, List[String])] = {
    //返回学号和对应的入学年份的Map集合
    def admissionYear(): Map[String, String] = {
      //构建一个临时的list用于生成所需要的rdd
      val resultTempListBuffer = new ListBuffer[(String, String)]
      for (i <- dataList) {
        val lines = i.split(",")
        val stuId = lines(0)
        val endTime = lines(3)
        resultTempListBuffer.append((stuId, endTime))
      }
      val rdd = sc.parallelize(resultTempListBuffer.toList)
      //让它的最后一个数据保留,即是最大年份
      val tempMap = rdd.sortByKey(true).collect().toMap
      //返回一个userid->semerster
      val resultBuff = new ListBuffer[(String, String)]
      val tempMapList = tempMap.toList
      for (i <- tempMapList) {
        //由于是迭代器的原因复制一下key
        val stuId = i._1
        //获得对应的日期类
        val timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")
        //经过清洗的数据不需要在判断是否可能出现异常
        val endDate = timeFormat.parse(i._2)
        //通过入学年份,上网时间的年,月计算学期,1900是年份的起始时间
        var semester = (endDate.getYear + 1900 - stuId.substring(0, 4).toInt) * 2
        if (endDate.getMonth + 1 > 6)
          semester = semester + 1
        //返回一个userid->semerster
        resultBuff.append((stuId, semester.toString))
      }
      resultBuff.toMap
    }

    val tempListBuff = new ListBuffer[(String, List[String])]
    val semesterMap = admissionYear
    for (i <- dataList) {
      val lines = i.split(",")
      val stuId = lines(0)
      val startTime = lines(2)
      //获得对应的日期类
      val timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")
      //经过清洗的数据不需要在判断是否可能出现异常
      val startDate = timeFormat.parse(startTime)
      //算出统计的年月,即开始时间格式化成yyyy-MM-01
      //先算出开始的年
      val startYear = (startDate.getYear + 1900).toString
      val startYearBuffer = new StringBuffer(startYear)
      //拼接成结果年月
      startYearBuffer.append("-").append((startDate.getMonth + 1).toString) //.append("-").append(getOnMonthtoDays(startTime).toString)
      /*构建一个(userId+"#"+onlineYearMonth+"#"+semester ->
      *hourOnlineCounts.toList)的RDD返回
      *首先构建一个List
      */
      val resultkey = stuId + "#" + startYearBuffer.toString + "#" + semesterMap(stuId)
      val tempTimeListBuff = new ListBuffer[String]
      for (i <- 4 to 27) {
        tempTimeListBuff.append(lines(i))
      }
      tempListBuff.append((resultkey, tempTimeListBuff.toList))
    }
    sc.parallelize(tempListBuff.toList)
  }

  //初步处理每一行的数据的具体方法
  def process(line: String) = {
    //重写一个获得天数的方法
    def getOnMonthtoDays(time: String): Int = {
      val lines = time.split("/")
      val day = lines(2).split(" ")
      day(0).toInt
    }

    val lines = line.split(",")
    //2015011123,2,2015/10/23 17:42,2015/10/23 23:36
    val startTime = lines(2)
    val endTime = lines(3)
    //获得对应的日期类
    val timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")
    //经过清洗的数据不需要在判断是否可能出现异常
    val startDate = timeFormat.parse(startTime)
    val endDate = timeFormat.parse(endTime)
    //考虑跨天跨月,年份不做要求,getMonth返回的是0-11的数
    val startMonth = startDate.getMonth + 1
    val endMonth = endDate.getMonth + 1
    val startDay: Int = getOnMonthtoDays(startTime)
    val endDay: Int = getOnMonthtoDays(endTime)
    //跨月天数加30在去减开始的天数
    //具体跨了几天
    //28-26-1=1,有一天是一直在上网
    var continued = 0
    if (endMonth > startMonth) {
      continued = (endMonth - startMonth) * 30 + (endDay + 30) - startDay
    } else {
      continued = endDay - startDay
    }
    //考虑在一天之内的持续小时数
    val startHour = startDate.getHours
    val endHour = endDate.getHours
    //从上机时间到下机时间的列对应加一,跨天则,在0-结束时间在加一
    if (continued > 0) {
      continued = continued - 1
      //把拆分出来的小时字段对应的加上上网的时间
      for (i <- 4 to 27) {
        lines(i) = (lines(i).toInt + continued).toString
      }
      //再把上机当天的持续小时加上,下机当天的加上即可
      //假定18点上机,对应下标开始为18+4,到23点+4,结束
      for (i <- startHour + 4 to 27) {
        lines(i) = (lines(i).toInt + 1).toString
      }
      //假设到第二天的5点,则只需要从0点到5点加一
      //下标从+4开始
      for (i <- 4 to endHour + 4) {
        lines(i) = (lines(i).toInt + 1).toString
      }
    } else {
      //这个时候说明没有跨天,直接加在从上机到下机的对应下标加一即可
      for (i <- startHour + 4 to endHour + 4) {
        lines(i) = (lines(i).toInt + 1).toString
      }
    }
    val resultline = lines.toList.mkString(",")
    //把处理完的数据写入全局变量中,方便下面数据的传递
    dataListBuffer.append(resultline)
  }

  //计算上网时间,考虑跨天
  def calculate_InternetTime(dataList: List[String], sc: SparkContext) = {
    //初步对每一行的数据进行处理
    dataList.foreach(process)
    //再次处理每一行数据,接受
    val acceptRDD = againprocess(dataListBuffer.toList, sc)
    //reduceByKey(24小时的值纵向相加)
    acceptRDD.reduceByKey((v1: List[String], v2: List[String]) => {
      //定义一个临时存储int类型的list
      val tempListBuff = new ListBuffer[Int]
      //遍历
      for (i <- v1) {
        tempListBuff.append(i.toInt)
      }
      //把数据给v1List,下面要清空
      val v1List = tempListBuff.toList
      //清空
      tempListBuff.clear()
      //同上
      for (j <- v2) {
        tempListBuff.append(j.toInt)
      }
      val v2List = tempListBuff.toList
      tempListBuff.clear()
      //合并
      for (i <- 0 to 23) {
        tempListBuff.append((v1List(i) + v2List(i)))
      }
      //定义一个返回集合
      val resultList = new ListBuffer[String]
      for (j <- 0 to 23) {
        resultList.append(tempListBuff(j).toString)
      }
      resultList.toList
    })//因为是list写到文件里不太好,在映射一下
      .map((v1) => {
      (v1._1, v1._2.mkString(","))
    }).saveAsTextFile(fileOutputPath)
  }


  def main(args: Array[String]): Unit = {
    //为local【1】,可以让数据都分到一起,AppName只是名,随意
    val conf = new SparkConf().setMaster("local[1]").setAppName("OnlineData")
    val sc = new SparkContext(conf)
    calculate_InternetTime(insertTimeFields, sc)
  }

}

3.用网情况分析

package Server

import org.apache.spark.{SparkConf, SparkContext}

import java.text.SimpleDateFormat
import scala.collection.mutable.ListBuffer
import scala.io.Source

/** ****************************************
 *
 * @ClassName UsingNet
 * @Description 分析用网的情况
 * @Author sanglong
 * @Date 2022/7/23 15:21
 * @Version 1.8
 *          *************************************** */

object UsingNet {
  //定义输入文件的路径,以及分析完成后的输出路径
  val fileInputPath = "G:\\datas\\output\\cleanData\\cleanData.csv"
  val fileOutputPath = "G:\\datas\\output\\UseingNet\\useNet"
  //临时暂存数据处理结果
  val tempListBuff = new ListBuffer[String]

  //返回学号和对应的入学年份的Map集合
  def admissionYear(dataList: List[String], sc: SparkContext): Map[String, String] = {
    //构建一个临时的list用于生成所需要的rdd
    val resultTempListBuffer = new ListBuffer[(String, String)]
    for (i <- dataList) {
      val lines = i.split(",")
      val stuId = lines(0)
      val endTime = lines(3)
      resultTempListBuffer.append((stuId, endTime))
    }
    val rdd = sc.parallelize(resultTempListBuffer.toList)
    //让它的最后一个数据保留,即是最大年份
    val tempMap = rdd.sortByKey(true).collect().toMap
    //返回一个userid->semerster
    val resultBuff = new ListBuffer[(String, String)]
    val tempMapList = tempMap.toList
    for (i <- tempMapList) {
      //由于是迭代器的原因复制一下key
      val stuId = i._1
      //获得对应的日期类
      val timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")
      //经过清洗的数据不需要在判断是否可能出现异常
      val endDate = timeFormat.parse(i._2)
      //通过入学年份,上网时间的年,月计算学期,1900是年份的起始时间
      var semester = (endDate.getYear + 1900 - stuId.substring(0, 4).toInt) * 2
      if (endDate.getMonth + 1 > 6)
        semester = semester + 1
      //返回一个userid->semerster
      resultBuff.append((stuId, semester.toString))
    }
    resultBuff.toMap
  }

  //2)生成学号,性别,熬夜次数,上网时长,上网年月,学期 字段
  def process(sc: SparkContext): List[String] = {
    //获得对应路径下的文本内容,清洗后的表
    val content = Source.fromFile(fileInputPath)
    //获得表的每一行的数据
    val rowList = content.getLines().toList.toBuffer
    //获得入学年份对应的集合
    val getSemesterMap = admissionYear(rowList.toList, sc)

    def lineProcess(line: String) = {
      val lines = line.split(",")
      //2015011123,2,2015/10/23 17:42,2015/10/23 23:36
      val stuId = lines(0) //学号
      val sex = lines(1) //性别
      val startTime = lines(2)
      val endTime = lines(3)
      //获得对应的日期类
      val timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")

      //重写一个获得天数的方法
      def getOnMonthtoDays(time: String): Int = {
        val lines = time.split("/")
        val day = lines(2).split(" ")
        day(0).toInt
      }

      //重写一个获得分钟的方法
      def getMinute(time: String): String = {
        val lines = time.split("/")
        val mm = lines(2).split(" ")
        mm(1)
      }

      //经过清洗的数据不需要在判断是否可能出现异常
      val startDate = timeFormat.parse(startTime)
      val endDate = timeFormat.parse(endTime)
      val startDay: Int = getOnMonthtoDays(startTime)
      val endDay: Int = getOnMonthtoDays(endTime)
      val endMinute = getMinute(endTime)
      //熬夜次数:如果跨夜或者没跨夜但是23:30后下网的 熬夜次数字段为一
      var number = 0

      //比较分钟时间是否超过了11:30的方法
      def OutOfRangeTime(endMinute: String) = {
        //用于判断是不是超过了11:30
        var boo = false
        //拆分
        val lines = endMinute.split(":")
        //获得小时
        val hour = lines(0).toInt
        //获得分钟
        val minute = lines(1).toInt
        if (hour > 23) {
          boo = true //超过了11:30
        } else if (hour == 23) {
          if (minute > 30) {
            boo = true //超过了11:30
          }
        }
        //返回即可,其余情况跨夜判断即可
        boo
      }

      //判断熬夜的字段应该为多少
      val continued = endDay - startDay
      if (continued > 0) {
        number = 1
      } else {
        if (OutOfRangeTime(endMinute)) {
          number = 1
        }
      }


      //上网时常
      val useNetTime = (endDate.getTime - startDate.getTime) / 3600000
      //上网年月
      val useNetYearMonth = (startDate.getYear + 1900).toString.concat("-").concat((startDate.getMonth + 1).toString)
      //获得学期
      val semester = getSemesterMap.get(stuId).mkString.toInt
      //拼接结果
      val resultStringBuffer = new StringBuffer()
      resultStringBuffer.append(stuId).append(",")
      resultStringBuffer.append(sex).append(",")
      resultStringBuffer.append(number.toString).append(",")
      resultStringBuffer.append(useNetTime).append(",")
      resultStringBuffer.append(useNetYearMonth).append(",")
      resultStringBuffer.append(semester)
      //返回值
      tempListBuff.append(resultStringBuffer.toString)
    }
    //2015011123,2,2015/10/23 17:42,2015/10/23 23:36
    //清洗后的数据实例
    rowList.foreach(lineProcess)
    tempListBuff.toList
  }

  //存储最大熬夜次数,最小熬夜次数,最大上网时间,最小上网时间
  val ResultMapListBuff = new ListBuffer[Int]
  //存储(number,onnettime)
  val tempCount = new ListBuffer[(Int, Int)]
  //存储userId+","+sex+","+onlineYearMonth+","+semester
  val resultListBuff = new ListBuffer[String]
  def againProcess(dataList: List[String], sc: SparkContext) = {
    //    map算子返回所有字段(把熬夜次数和上网时长展开),用reduceByKey纵向求和
    val acceptRDD = sc.parallelize(dataList)
    val tempRDD=acceptRDD.map((v1: String) => {
      val lines = v1.split(",")
      //熬夜次数
      val number = lines(2)
      //上网时长
      val useNetTime = lines(3)
      val key = lines(0).concat(",")
        .concat(lines(1)).concat(",")
        .concat(lines(4)).concat(",")
        .concat(lines(5))
      val value1 = List(number, useNetTime)
      //返回值
      (key, value1)
    }).reduceByKey((v1: List[String], v2: List[String]) => {
      //定义一个临时存储int类型的list
      val temp1ListBuff = new ListBuffer[Int]
      //遍历
      for (i <- v1) {
        temp1ListBuff.append(i.toInt)
      }
      //把数据给v1List,下面要清空
      val v1List = temp1ListBuff.toList
      //清空
      temp1ListBuff.clear()
      //同上
      for (j <- v2) {
        temp1ListBuff.append(j.toInt)
      }
      val v2List = temp1ListBuff.toList
      temp1ListBuff.clear()
      //合并
      for (i <- 0 to 1) {
        temp1ListBuff.append((v1List(i) + v2List(i)))
      }
      //定义一个返回集合
      val resultList = new ListBuffer[String]
      for (j <- 0 to 1) {
        resultList.append(temp1ListBuff(j).toString)
      }
      resultList.toList
    }).map(v1 => {
      val number = v1._2(0).toString().toInt
      val netTime = v1._2(1).toString().toInt
      tempCount.append((number, netTime))
      resultListBuff.append(v1._1)
      resultListBuff.toList
    }).collect()//没有.collect不执行map
    //设置初始值
    var maxNumber = tempCount(0)._1
    var minNumber = tempCount(0)._1
    var maxOnNetTime = tempCount(0)._2
    var minOnNetTime = tempCount(0)._2
    for (i <- tempCount) {
      //获得最大熬夜次数,最小熬夜次数
      maxNumber = Math.max(maxNumber, i._1)
      minNumber = Math.min(minNumber, i._1)
      //获得最大上网时间,最小上网时间
      maxOnNetTime = Math.max(maxOnNetTime, i._2)
      minOnNetTime = Math.min(minOnNetTime, i._2)
    }
    //添加进集合中
    ResultMapListBuff.append(maxNumber)
    ResultMapListBuff.append(minNumber)
    ResultMapListBuff.append(maxOnNetTime)
    ResultMapListBuff.append(minOnNetTime)
  }

  //计算能力值,把处理后的Rdd给拿过来
  def getAbility(resultList: List[String],maxMinList:List[Int],tempCount:List[(Int, Int)],sc:SparkContext) = {
    //存储处理计算后的能力值
    val tempListBuff=new ListBuffer[String]
    //遍历计算
    //每条数据的值-该数据的最小值)/(该数据最大值-该数据最小值)
    //		程度=能力值*权重
    //30%,70%
    for(i<-tempCount){
      val temp1=(i._1-maxMinList(1)).toDouble/(maxMinList(0)-maxMinList(1))*0.3
      val temp2=(i._2-maxMinList(3)).toDouble/(maxMinList(2)-maxMinList(3))*0.7
      val temp=temp1+temp2
      tempListBuff.append(temp.toString)
    }

    //拼接最终结果
    val resultListBuff=new ListBuffer[String]
    //遍历前半部分字符串,用下标,两个集合的长度是一样的
    for (i<-0 to resultList.size-1){
      resultListBuff.append(resultList(i).concat(",").concat(tempListBuff(i)))
    }
    //返回结果
    sc.parallelize(resultListBuff.toList).saveAsTextFile(fileOutputPath)
  }

  def main(args: Array[String]): Unit = {
    //为local【1】,可以让数据都分到一起,AppName只是名,随意
    val conf = new SparkConf().setMaster("local[1]").setAppName("UsingNetData")
    val sc = new SparkContext(conf)

    againProcess(process(sc), sc)
    //写入
    getAbility(resultListBuff.toList,ResultMapListBuff.toList,tempCount.toList,sc)
  }


}

注释:这部分的数据运行出来后是自己改的名,生成的是和MR一样的形式的输出数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值