package com.zyc.spark
import com.zyc.utils.DateUtils
import org.apache.spark.rdd.RDD
import org.apache.spark.{Partitioner, SparkConf, SparkContext}/**
* Created with IntelliJ IDEA.
* Author: zyc2913@163.com
* Date: 2020/9/25 16:30
* Version: 1.0
* Description: 转换算子的应用
*/
object StudyTransformation {
def main(args: Array[String]): Unit = {
//配置spark环境
val conf = new SparkConf()
.setMaster("local[2]")
.setAppName("demo2")
val sc = new SparkContext(conf) /**
* 转换算子
* RDD -> transformation -> RDD
*/
/**
* 1.map 对每个元素操作map
* 1.1声明 def map(f: T => U): RDD[U]
* 1.2参数 一个一元函数,参数是原RDD的元素类型,返回值可以改变类型
* 1.3返回值 新的RDD,泛型是f的返回值类型
* 1.4作用 将原RDD中的每个元素应用到f中,将返回值收集到一个新的RDD中
* 1.5应用举例 收集日志文件中的ip,time(访问时间),rCode(登录标识码)
*/
//通过读取文件创建RDD
val rdd1:RDD[String] = sc.textFile("C:\\Users\\Administrator\\Desktop\\book\\logs\\access.log-20190926")
val rdd2 = rdd1.map(line => {
val str = line.split("\\s+")
val ip = str(0) // 小标为0的字符串为ip
val time = DateUtils.dateFormat(str(3).tail) //调用工具类的日期转换函数将下标为3的字符串的尾部进行转换
var rCode = 0 //定义登录标识码初始值为0
try {
rCode = str(8).toInt
// rCode的值是下标为8的字符串,将String类型转成Int型
} catch {
case e: Exception =>
}
(ip, time, rCode) //最后一行是返回值
})
//rdd2.foreach(println) /**
* 2.filter 过滤器
* 2.1声明 def filter(f: T => Boolean): RDD[T]
* 2.2参数 一元函数,参数是原RDD中的元素,返回值是Boolean
* 2.3返回值 和原RDD泛型一致的RDD
* 2.4作用 过滤元素 (f返回True的元素将被留下)
* 2.5应用举例 收集rCode为200和404的访问信息(ip, time, rCode)
*/
rdd2.filter(_._3 == 200) //留下rCode为200的函数返回值
// .foreach(println) //打印到控制台
rdd2.filter(_._3 == 404) //留下rCode为404的函数返回值
// .foreach(println) //打印到控制台 /**
* 3.flatMap 二维转换成一维map
* 3.1声明 def flatMap(f: T => TraversableOnce[U]): RDD[U]
* 3.2参数 一个一元函数,参数是原RDD的元素类型,返回值是一个集合
* 3.3返回值 是一个f的返回值泛型的RDD
* 3.4作用 将二维集合变成一维集合
* 3.5应用举例 统计所有ip中0到9的数字出现的次数
*/
rdd2.flatMap(x => {
val res1:String = x._1
val res2:String = res1.replace(".", "")
val res3:Array[String] = res2.split("")
res3
})
.map((_,1)) //写成二元组的形式
.reduceByKey(_+_) //根据key聚合统计value
//.foreach(println)
//上面的也可以写成下面的样子
val rdd3:RDD[String] = rdd2.flatMap(_._1.replace(".", "").split(""))
rdd3.map((_,1))
.reduceByKey(_+_)
//.foreach(println) /**
* 4.mapPartitions 按分区数map
* 4.1声明 def mapPartitions( f: Iterator[T] => Iterator[U],preservesPartitioning: Boolean = false): RDD[U]
* 4.2参数 第一个参数:一个一元函数,参数是一个原RDD泛型的迭代器,这个迭代器每次传入一个分区的全部元素,返回值也是一个迭代器,泛型不限
* 4.3返回值 RDD[U] 泛型为f返回值泛型的RDD
* 4.4作用 之前map是每次拿到一个元素,mapPartitions一次性拿到一个分区的所有元素,在将处理完的结果放回到新的RDD中
*/
val rdd4:RDD[Int] = sc.makeRDD(1 to 10) //1到10的数组
//rdd4.map(_+1).foreach(println) //RDD每个元素+1,然后打印到控制台,运算了10次
//rdd4.mapPartitions(iter => iter.map(_+1)).foreach(println) //RDD按分区数map,每个元素+1然后打印到控制台,运算了2次(设置的核心数为2,则默认分区数为2)
rdd4.mapPartitions((iter:Iterator[Int]) => {
Iterator(iter.toList.mkString("|")) //把数组转换成List,根据分区数分成了2个list,然后把元素按|分隔开
})
//.foreach(println) //打印结果为6|7|8|9|10 1|2|3|4|5 /**
* 5.mapPartitionsWithIndex 按分区数的下标map (下标默认从0开始,下标也叫索引)
* 5.1声明 def mapPartitionsWithIndex(
* 分区索引
* f: (Int, Iterator[T]) => Iterator[U],
* preservesPartitioning: Boolean = false): RDD[U]
* 5.2参数 与mapPartitions类似,多了一个int类型的参数,接收传进来的分区索引
* 5.3返回值 RDD[U]
* 5.4作用 与mapPartitions类似
*/ rdd4.mapPartitionsWithIndex((index,iter) => {
val tuple:(Int,String) = (index, iter.mkString("|")) //二元组类型(下标,按|分隔的数组)
Iterator(tuple)
})
//.foreach(println) //打印结果:(0,1|2|3|4|5) (1,6|7|8|9|10) ( 设置的核心数为2,默认的分区数就为2,所以分区的下标就是0,1) /**
* 6.sample 计算机的随机算法,可以保证如果输入参数不同-->>输出结果不同
*6.1声明 def sample(
* withReplacement: Boolean, //是否放回 true表示放回,取的值可能会重复;false表示不放回,取的值不会重复
* fraction: Double, //抽样比例 不是非常精准(可能多几个也可能少几个),即抽出的个数占总个数的比值
* seed: Long = Utils.random.nextLong //随机种子
* ): RDD[T]
* 6.2参数
* 6.3返回值 和原RDD类型相同的RDD
* 6.4作用 在海量数据中进行抽样
* 6.5应用举例:对一个数组(1到100)进行抽样
*/
val rdd5:RDD[Int] = sc.makeRDD(1 to 100) //定义一个1到100的数组
//rdd5.sample(false,0.1).foreach(println) //从数组(1到100)中不放回(false)的取总个数的比例为0.1(百分之10)的元素(因为是比例所以不精准,可能是10个,可能是9个,也可能是11个)打印到控制台
/*
takeSample精确抽样;sample模糊抽样
*/
//rdd5.takeSample(false,10).foreach(println) //从数组中不放回的随机取10个元素打印到控制台 /**
* 7.union 类似于集合中的并集 A ∪ B
* 7.1声明 def union(other: RDD[T]): RDD[T]
* 7.2参数 另外一个和原RDD类型相同的RDD
* 7.3返回值 和原RDD类型相同
* 7.4作用 合并RDD
* 7.5应用举例:把两个数组合并到一起(并集)
*/
val res1 = sc.makeRDD(1 to 5)
val res2 = sc.makeRDD(3 to 7)
//res1.union(res2).foreach(println) //将res1与res2合并(取并集有重复的元素)打印到控制台 /**
* 8.intersection 类似于集合中的交集 A ∩ B
* 8.1声明 def intersection(other: RDD[T]): RDD[T]
* 8.2参数 另外一个和原RDD类型相同的RDD
* 8.3返回值 和原RDD类型相同
* 8.4作用 交集
* 8.5应用举例:取两个数组中相同的元素(交集)
*/
//res1.intersection(res2).foreach(println) //取res1与res2中的相同元素(交集)打印到控制台 /**
* 9 distinct 去重
* 9.1声明
* 9.2参数
* 9.3返回值
* 9.4作用
* 9.5应用举例:去除数组中的重复元素
*/
//sc.makeRDD(Array(1,2,3,4,2,1,6,5,3,9)).distinct().foreach(println) //对数组去重后打印到控制台 /**
* 10 partitionBy 适用于key-value型,该函数来自于PairRDDFunctions.scala
* 10.1声明 def partitionBy(partitioner: Partitioner): RDD[(K, V)]
* 10.2参数 是一个分区器对象的实例
* 10.3返回值 和原RDD类型相同
* 10.4作用 按照自定的分区器,对RDD中的元素进行分区
*/
val rdd6:RDD[Int] = sc.makeRDD(1 to 10)
val rdd7:RDD[(Int,Int)] = rdd6.map(x => (x, x)) //将数组转成key-value型
rdd7.partitionBy(new Partitioner {
override def numPartitions: Int = 2 //设置分区数为2 override def getPartition(key: Any): Int = key.asInstanceOf[Int] % 2 //将key分成奇数和偶数
}).map(_._1) //再转换成数组
.mapPartitionsWithIndex((index,iter)=>Iterator((index,iter.mkString("|")))) //按分区索引分,将元素用|分隔开
// .foreach(println) //打印结果(0,2|4|6|8|10) (1,1|3|5|7|9)
}}
spark GC时间显示 spark 日期转换
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章