RDD常用算子

spark集群提交任务的命令:
bin/spark-submit --master spark://node-1.XXXXX.com:7077,node-2.xxxx.com:7077
--executor-memory 512mb --total-executor-cores 4
--class com.xxxx.day1.WordCount /root/spark-1.0.jar 
hdfs:// node-1.xxxx.com:9000/wc hdfs://node-1.xxx.com:9000/out


Spark一个分布式计算系统,可以替代MR编程模型


下载spark-2.1.1-hadoop2.6
java8  scala2.11.x


安装spark只要安装JDK就可以了。因为scala已经内置进去了
先解压,然后修改两个配置文件conf  spark-env.sh slaves


sbin/start-all.sh
  start-master.sh -> Master
  start-slaves.sh -> 读取slave配置文件,然后通过ssh的方法向slaves中机器发送启动Worker命令


配置高可用的Spark集群
  首先安装zk集群
  在spark-env.sh中加入一个选项


spark-shell 通过一个交互式的命令行,编写spark应用程序
bin/spark-shell --master spark://node-1.xxx.com:7077,node-2.xxx.com:7077
--executor-memory 5g --total-executor-cores 50


sc.textFile("hdfs://node-1.xxx.com:9000/wc").flatMap(_.split("")).map((_,1)).reduceByKey(_+_)
    .sortBy(_._2,false).saveAsTextFile("hdfs://node-1.xxx.com:9000/out")




sortBy传入的只是规则,对原本数据类型没有改变。例如sortBy(x=>x + "",true),按照字典序来排,若原本x属于Int类型,则排序后仍然是Int类型


默认情况下,RDD的分区(partition)跟指定的核数是一样的。
可以使用:
val rdd1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9,10,11,12,13),2)
参数2来指定分区

如果从hdfs读取文件。则RDD分区数量跟文件切片数量有关。HDFS默认文件切片块大小为128M



join操作:
只有key,value类型的数据才会被join
scala>val rdd1 = sc.parallelize(List(("tom",1),("jerry",2),("kitty",3)))

scala>val rdd2 = sc.parallelize(List(("jerry",9),("tom",8),("shuke",7),("tom",2)))

scala>val rdd3 = rdd1.join(rdd2)

scala>rdd3.collect
res0:Array[(String,(Int,Int))] = Array((tom,(1,2)),(tom,(1,8)),(jerry,(2,9)))

scala>val rdd3 = rdd1.leftOuterJoin(rdd2)

scala>rdd3.collect
res1:Array[(String,(Int,Option[Int]))] = Array((kitty,(3,None)),(tom,(1,Some(8))),(tom,(1,Some(2))),(jerry,(2,Some(9))))
Some代表有值,None代表没值

CompactBuffer:是一个集合。——groupByKey后会出现。

=======例子1=================


val rdd2 = sc.parallelize(List("a","b","c","d","e","f"),2)

def func2(index:Int,iter:Iterator[(String)]):Iterator[String] = {
    iter.toList.map(x => "[partId": + index + ",val:" + x + "]").iterator
}

rdd2.aggregate("")(_+_,_+_)
rdd2.aggregate("=")(_+_,_+_)

scala>rdd2.mapPartitionsWithIndex(func2).collect

scala>rdd2.aggregate("")(_+_,_+_)
res0:String = abcdef

scala>rdd2.aggregate("")(_+_,_+_)
res1:String = defabc

scala>rdd2.aggregate("|")(_+_,_+_)
res2:String = ||abc|def

========例子2====================


scala>val rdd3 = sc.parallelize(List("12","23","345","4567"),2)


scala>rdd3.aggregate("")((x,y) => math.max(x.length,y.length).toString,(x,y) => x + y)
res3:String = 24  //res3:String = 42


scala>rdd3.aggregate("x")((x,y) => math.max(x.length,y.length).toString,(x,y) => x + y)
res4:String = x24  //res4:String = x42


scala>val rdd4 = sc.parallelize(List("12","23","345",""),2)


scala>rdd4.aggregate("")((x,y) => math.min(x.length,y.length).toString,(x,y) => x + y)
res5:String = 10 //res5:String = 01  ,注意这边的toString


====================================

repartition和coalesce  :都是重新分配partition,区别在于repartition有suffer。coalesce无法使得partition数量变大。

====================================
countByKey/countByValue
filterByRange
flatMapValues(_.split(""))

scala>val a = sc.parallelize(List(("a","1,2"),("b","3 4")))
scala>a.flatMapValues(_.split(" ")).collect
res0:Array[(String,String)] = Array((a,1),(a,2),(b,3),(b,4))

===================================
拉链操作 zip


scala>val rdd4 = sc.parallelize(List("dog","cat","gnu","salmon","rabbit","turkey","wolf","bear"))


scala>val rdd5 = sc.parallelize(List("1","2","1","3","1","4","2","1"))


scala>rdd4.zip(rdd5).collect
res0:Array[(String,Int)] = Array((dog,1),(cat,2),(gnu,1),(salmon,3),(rabbit,1),(turkey,4),(wolf,2),(bear,1))


===================================
集合操作

scala>val lst = List(1)
res0:List[Int] = List(1)

scala>val l2 = lst :+ 2
ls:List[Int] = List(1,2)

scala>lst ++l2
res0:List[Int] = List(1,1,2)

==================================

重要算子:combineByKey() 

==================================
rdd.toDebugString  查看依赖关系
==================================
自定义分区器

计算每个学科内数量最多的前2个。

val subjects = reduced.map(_._1._1).distinct().collect()
    //定义分区器
    val subPartitioner: SubjectPartitioner = new SubjectPartitioner(subjects)
    //安装自定义分区器的规则shuffle
    val partitioned: RDD[(String, (String, Int))] = reduced.map(t => (t._1._1,(t._1._2,t._2))).partitionBy(subPartitioner)
    //每个分区中只有一个学科
    //拿出来iterator转为List计算,然后再转为iterator
    val result: RDD[(String, (String, Int))] = partitioned.mapPartitions(_.toList.sortBy(_._2._2).reverse.take(2).iterator)
//导入spark的partitioner包
  class SubjectPartitioner(subjects: Array[String]) extends Partitioner {
    //定义分区规则
    val rules = new mutable.HashMap[String,Int]()
    var i = 0
    for(sub <- subjects) {
      rules += (sub -> i)
      i += 1
    }
    //定义分区数量
    override def numPartitions: Int = subjects.length + 1
    //根据传入的key决定该条数据到哪个分区
    override def getPartition(key:Any): Int = {
      val k = key.toString
      rules.getOrElse(k,0)
    }
  }
Tips:显示类型,有两种方法,一种是Ctrl+alt+v,一种是在变量后加上“.var”,然后按制表符

当rdd从HDFS多次读取相同的数据时,可以调用 rdd.cache()来缓存数据。当内存空间不足时,不会全部存储。
当数据不使用时,使用 rdd.unpersist(true)来释放资源。


rdd.persist(StorageLevel.MEMORY_ONLY_SER)。也是用来缓存数据的方法,而且可以传入StorageLevel参数。
可以指定RDD的存储级别。MEMORY_ONLY_SER表示将数据序列化后再存到内存中。



文件以java对象直接读入内存占用的内存会比原文件大。例如37M会变成116M等等。解决方法是使用压缩算法
或者序列化。
====================
CheckPoint的使用技巧
在hdfs中设置一个目录。用来存放计算中间结果
scala>sc.setCheckpointDir("hdfs://node-1/ck0001")


scala>val rdd1 = sc.textFile("hdfs://node-1/xxx.log")


scala> rdd2 = rdd1.filter(_contains("java"))


scala>rdd2.chekpoint()   


scala>rdd2.count   //在对应ck0001下生成对应结果。


scala>rdd2.count   //直接用ck0001下的数据。




如果一个rdd同时被cache和checkpoint,优先从cache中取数据。


RDD和RDD之间存在着依赖关系,分两种。有shuffle就是宽依赖,没有shuffle就是窄依赖。


DAG 有向无环图
触发Action时才会形成一个完整的DAG
触发Ation任务就要提交到集群执行了。
任务在提交集群之前,要进行一些准备,这些准备工作都是在Driver端
    1、构建DAG
    2、将DAG切分成1到多个Stage
    3、任务执行分阶段进行,先提交前面的Stage,前面的Stage执行完后,后面stage才能继续执行,因为后面的Stage要依赖前面Stage计算的结果
    4、一个Stage生成多个Task提交的Executor中,Stage生成的Task的数量跟该阶段RDD的分区数量一致


=========================
创建一个rules,如果在Driver端创建的一个变量,并且在传入到RDD方法的函数中,RDD方法中传入的函数是在Executor的Task中执行的,
Driver会将这个在Driver中定义的变量发送给每一个Task。
解决方案:广播变量


//将Driver端的变量广播到属于自己的所有Executor
val broadcast: Broadcast[Map[String,String]] = sc.broadcast(rules)


//在Executor端拿到广播变量中的值
val r:Map[String,String] = broadcast.value
val nation_name = r(nation_code)


==========================
//利用foreachPartition将数据写入数据库
//传入的是分区
def data2MySQL (part: Iterator[(String,Int)]):Unit = {
  //创建一个jdbc连接
  val conn: Connection = DriverManager.getConnection("jdbc:mysql://localhost:3306?charactorEncoding=utf-8","root","123456")
  val prepareStatement = conn.prepareStatement("INSERT INTO access_log (provinc,count) values (?,?)")
  //写入数据
  part.foreach(data => {
    prepareStatement.setString(1,data._1)
prepareStatement.setInt(2,data._2)
prepareStatement.executeUpdate()
  })
  prepareStatement.close()
  conn.close()
}
=============================
JdbcRDD类的使用:从数据库读取数据到RDD中,然后对数据进行处理。
=============================
多比较条件排序。可以往sortBy()里传入自定义查询类


userRDD.sortBy(t => User(t._1,t._2,t._3,t._4))


自定义查询类举例:


case class User(id:Long, name:String, age:Int, fv:Int) extends Comparable[User] {
  override def compareTo(that:User):Int = {
    //疑问,为什么这么写
    if(this.fv == that.fv) {
      this.age - that.age
    } else {
      that.fv - this.fv
    }
  }


}


==============================
spark 1.6版本使用spark SQL
scala>val lines = sc.textFile("hdfs://node-1.xxxxxxx.com:9000/person.txt")
scala>case class Person(id:Long,name,String,age:Int,fv:Int)
scala>val userRDD = lines.map(_.split(",")).map(arr => Person(arr(0).toLong),arr(1),arr(2).toInt,arr(3).toInt)
scala>val pdf = userRDD.toDF()
scala>pdf.registerTempTable("t_user")
scala>val sqlContext = new org.apache.spark.sql.SQLContext(sc)
scala>val result = sqlContext.sql("SELECT * FROM t_user order by fv desc,age asc")
scala>result.show()
==============================
如何创建DataFrame对象
//方法一,RDD里面存Person对象(spark2.x之前的方法)
//对数据进行整理并映射成case class(将RDD和case class进行关联)
val personRDD:RDD[Person] = lines.map(lines => {
  val fields = line.split("[,]")
  val id = fields(0).toLong
  val name = fields(1)
  val age = fields(2).toInt
  val fv = fields(3).toInt
  Person(id,name,age,fv)
})


//创建SQLContext
val sqlContext = new SQLContext(sc)
//导入隐式转换
import sqlContext.implicits._1
//将RDD转换成DataFrame
val personDFS = personRDD.toDF()
//将DataFrame注册成临时表
personDF.registerTempTable("t_person")


//执行SQL,sql方法是一个Transformation,不会执行任务
val result:DataFrame = sqlContext.sql("SELECT name,age,fv FROM t_person ORDER BY fv DESC")
//触发action
result.show()
//释放资源
sc.stop()


//方法二,RDD里面存Row,同时需要有个schema与Row进行匹配(spark2.x之前的方法)
val rowRDD:RDD[Row] = lines.map(lines => {
  val fields = line.split("[,]")
  val id = fields(0).toLong
  val name = fields(1)
  val age = fields(2).toInt
  val fv = fields(3).toInt
  Row(id,name,age,fv)
})


//创建SQLContext
val sqlContext = new SQLContext(sc)
//导入隐式转换
import sqlContext.implicits._1


val schema = StructType(
  List(
    StructField("id",LongType,true),
    StructField("name",StringType,true),
    StructField("age",IntegerType,true),
    StructField("fv",IntegerType,true)
  )
)


val pdf:DataFrame = sqlContext.createDataFrame(rowRDD,schema)


//将DataFrame注册成临时表
pdf.registerTempTable("t_person")




//方法三 DataSet
val session = SparkSession
  .builder()
  .appName("HelloDataSet")
  .master("local[*]")
  .getOrCreate()
  
//通过sparkSession获得SparkContext  
val lines:RDD[String] = session.sparkContext.textFile("hdfs://xxxxx")
 
val rowRDD:RDD[Row] = lines.map(lines => {
  val fields = line.split("[,]")
  val id = fields(0).toLong
  val name = fields(1)
  val age = fields(2).toInt
  val fv = fields(3).toInt
  Row(id,name,age,fv)
})
 
val schema = StructType(
  List(
    StructField("id",LongType,true),
    StructField("name",StringType,true),
    StructField("age",IntegerType,true),
    StructField("fv",IntegerType,true)
  )
)
 
val pdf:DataFrame = session.createDataFrame(rowRdd,schema)
pdf.createTempView("v_person")
val result:DataFrame = session.sql("select * from v_person where id > 1 or by fv desc")
result.show()
session.close()




========例子=========


val session = SparkSession
  .builder()
  .appName("HelloDataSet")
  .master("local[*]")
  .getOrCreate()
  
//通过sparkSession获得SparkContext  
val lines:Dataset[String] = session.read.textFile("hdfs://xxxxx")
//导入session对象中的隐式转换
import session.implicits._


val words:Dataset[String] = lines.flatMap(_.split(""))


//DSL
//为了可以使用agg中的聚合函数,导入spark sql中的函数
import org.apache.spark.sql.functions._
val result:Dataset[row] = words.groupBy($"value" as "word").agg(count(*) as "count").sort($"count" desc)
























































  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值