sparkcore练习_1,RDD转化为RDD[LabelPoint]和map-side-join以及将结果(RDD/dataframe)输出到一个文件保存

本文详细介绍了如何使用Spark处理大规模数据集,包括网络流量数据的统计与特征转换,以及利用LabelPoint进行机器学习。同时,展示了如何处理数据集中的ID匹配问题,通过map-side-join优化性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 数据集net.gz为网络流量数据, 数据集每条记录展现每个连接的信息, 最后一列为攻击的标签

(1) 请统计, 出现的攻击类型对应的攻击次数
(2) 为了输入给算法, 请将RDD 类型转换为RDD[Labelpoint]
( Labelpoint为Spark Vector)

(1)不使用labelpoint:

package homework.chapter2

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

/**
 *
 * @author smallheroic
 * @Date 2019-12-08 15:11
 *
 */
object homework01 {

  def main(args: Array[String]): Unit = {
    val conf =  new SparkConf().setAppName("ch2homework01").setMaster("local[4]")
    val sc = new SparkContext(conf)
    //val spark = SparkSession.builder().appName("ch2homework1").master("local[4]").getOrCreate()
    //import spark.implicits._
    val data = sc.textFile("file:///E://FTP//spark//2-sparkCore1//kddcup.data.gz").flatMap(_.split("\n")).map(line =>
      ((line.split(",").reverse(0)), 1)).reduceByKey(_+_).sortBy(_._2,false).collect().foreach(println)
  }
}

(2)使用labelpoint,机器学习特征转化word2VC还不是很熟练,暂时用累加一的方式做标签

package homework.chapter2


import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.{SparkConf, SparkContext}


/**
 *
 * @author smallheroic
 * @Date 2019-12-08 15:11
 *
 */
object homework01 {

  def main(args: Array[String]): Unit = {
    val conf =  new SparkConf().setAppName("ch2homework01").setMaster("local[4]")
    val sc = new SparkContext(conf)

    val rdd = sc.textFile("file:///E://FTP//spark//2-sparkCore1//kddcup.data.gz").map(line =>
     ((line.split(",").reverse(0)), 1)).reduceByKey(_+_).sortBy(_._2,true).map(x=>(x._1,x._2))

    rdd.collect().foreach(println)

    var y:Double= 0
    val labeledPoint = rdd.map { x =>
      y+=1.0//标签每次加一
      LabeledPoint(
        y, Vectors.dense(x._2))
    }
    labeledPoint.collect().foreach(println)


  }
}

2. 数据集art.txt中存储id 和 姓名( 用制表符/t 分割) , art_alias.txt 存储正确ID 和错误ID 的对应关系, 编写程序, 将art.txt 中id 到art_alias.txt中匹配出正确的ID,并组成新的RDD[(id,name)]。

  提示:在处理art.txt 数据集过程中会遇到数据不合规的问题, 合理使用Some 和 None 解决此问题。
  在实际情况中往往art.txt 数据集会随着系统的运行时间增长变得很大, 利用map side join 思想解决上面的的问题。

最开始没有想到用map-side-join导致运行时间及其长,非常不好

package homework.chapter2

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

import scala.collection.mutable.ArrayBuffer

/**
 *
 * @author smallheroic
 * @Date 2019-12-08 20:22
 *
 */
object homework02 {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("homework2").setMaster("local[4]")
    val sc = new SparkContext(conf)

    var arr = new ArrayBuffer[(String,String)]()
    //不用map-side-join
    val data = sc.textFile("E:\\FTP\\spark\\2-sparkCore1\\artist_data.txt").filter { line =>
      var strs = line.split("\t")
      strs.length == 2
    }.map(line =>
        (line.split("\t")(0), line.split("\t")(1))).collectAsMap()

    val alias = sc.textFile("E:\\FTP\\spark\\2-sparkCore1\\artist_alias.txt").filter { line =>
      var strs = line.split("\t")
      strs.length == 2
    }.map (line =>
        (line.split("\t")(0), line.split("\t")(1))
    ).collectAsMap()


    for(id <- data.keySet)
      for (cid <- alias.keySet)
        if (id == alias.get(cid))
          arr.append((cid,data.get(id).toString))
    arr.foreach(println)
    }
  }

用了map-side-join之后,速度直线上升。
map-side-join:
将少量的数据转化为Map进行广播,广播会将此 Map 发送到每个节点中,如果不进行广播,每个task执行时都会去获取该Map数据,造成了性能浪费。
对大数据进行遍历,使用mapPartition而不是map,因为mapPartition是在每个partition中进行操作,因此可以减少遍历时新建broadCastMap.value对象的空间消耗,同时匹配不到的数据也不会返回()。

package homework.chapter2

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

import scala.collection.mutable.ArrayBuffer

/**
 *
 * @author smallheroic
 * @Date 2019-12-08 20:22
 *
 */
object homework02 {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("homework2").setMaster("local[4]")
    val sc = new SparkContext(conf)

 //map-side-join
    val data = sc.textFile("E:\\FTP\\spark\\2-sparkCore1\\artist_data.txt").filter { line =>
      var strs = line.split("\t")
      strs.length == 2
    }.map(line =>
      (line.split("\t")(0), line.split("\t")(1)))

    val alias = sc.textFile("E:\\FTP\\spark\\2-sparkCore1\\artist_alias.txt").filter { line =>
      var strs = line.split("\t")
      strs.length == 2
    }.map (line =>
      (line.split("\t")(1), line.split("\t")(0))//错误id做key,正确id做val
    ).collectAsMap()

    val alias_bc= sc.broadcast(alias)

    val res = data.mapPartitions(iter=>{
      val aliasMap = alias_bc.value
      val arrayBuffer = ArrayBuffer[(String,String)]()
      iter.foreach{case(wid,name)=>{
        if(aliasMap.contains(wid)){
          arrayBuffer.+=((aliasMap.getOrElse(wid,""),name))
        }
         arrayBuffer.+=((wid,name))
      }}
      arrayBuffer.iterator
    }
    )
    res.foreach(println)
    
    if (!new File("E:\\table\\homework2_out").exists())
      return
    else if (new File("E:\\table\\homework2_out").isDirectory()) {
      new File("E:\\table\\homework2_out").delete()
      println(new File("E:\\table\\homework2_out") + ":  文件被删除")
      return
    }
    //saveAstextFile默认是将RDD输出到多个文件的,因此我们需要通过方法coalesce(1)来设置,从而将RDD输出到一个文件中。
    res.coalesce(1).saveAsTextFile("E:\\table\\homework2_out")
  }
 }

另一种实现,for的守卫

  //另一种,用for的守卫实现
    val res1= data.mapPartitions(iter=>{
      val aliasMap1 = alias_bc.value
      for{
        (wid,name)<-iter
        if(aliasMap1.contains(wid))
      } yield (aliasMap1.getOrElse(wid,""),name)
    })
    res1.foreach(println)

将RDD输出到一个文件

saveAstextFile默认是将RDD输出到多个文件的,因此我们需要通过方法coalesce(1)来设置,从而将RDD输出到一个文件中。

    res.coalesce(1).saveAsTextFile("E:\\table\\homework2_out")

将dataframe保存到一个csv

dataframe保存到一个文件格式为‘csv’,repartition(1)将之前分区的多个输出重新合并到一个分区

   df.repartition(1).write.format("csv").save("E://table//local_22_out//")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值