文章目录
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//")