祝各位道友念头通达
GitHub Gitee 语雀 打赏

spark的UDF操作,RDD与DataFrame转换,RDD DataFrame DataSet的分析

1 >spark的UDF操作

理解:就是在sql中查询语句中提供了max(),avg(),min(),count()等函数操作, 同样的在spark中也有这些函数,但是用户的需求是多变的,比如:

select name,age,length(name)/name.length from user

很明显,不管是使用length(name)或是name.length都不可能实现这种效果,  于是spark提供UDF的操作可以实现这样的效果

代码如下:

 val conf = new SparkConf().setMaster("local").setAppName("json")
 val spark = SparkSession.builder().config(conf).getOrCreate()

 def fun1(): Unit ={
   //得到conf
   val people:DataFrame = spark.read.json("E:\\user.json")
   //通过SQL语句操作dataFrame
   people.createTempView("user")

   import spark.sql
   spark.udf.register[Int,String]("len",lengthName) //注册在spark中
   sql("select name,len(name) from user").show() 

 }
  //该方法需要注册在spark里
 def lengthName(name:String): Int ={
    name.length
 }

执行:

 

2 >RDD与DataFrame 相互转化

  >通过样例类转化: 

  /**
    * rdd与dataframe互操作
    *   1.通过样例类进行转换
    *   2.通过编程的方式进行转换
    */
  //1.通过样例类进行转化
  case class People(name:String, age:Int)  //样例类
  def fun2(): Unit ={
    val sc = spark.sparkContext
    val rdd  = sc.parallelize(Array("张三 12","成吉思汗 20","李四 33","占城 45"))
    val rddT = rdd.map(x=>{
      val p = x.split(" ")
      People(p(0),p(1).trim.toInt)
    })
    import spark.implicits._    //隐式转化
    val dataFrame:DataFrame = rddT.toDF  //将RDD转化dataFrame
    dataFrame.show()
    println(rdd.collect().toBuffer)
    println(dataFrame.rdd.collect().toBuffer)  //将dataFrame转化为RDD
    println(dataFrame.javaRDD.collect())     //同下,输出结果一样,
    println(dataFrame.toJavaRDD.collect())
  }

 通过查看源码: toJavaRDD与javaRDD都一样

输出结果:

dataFrame.show() 的输出
+----+---+
|name|age|
+----+---+
|  张三| 12|
|成吉思汗| 20|
|  李四| 33|
|  占城| 45|
+----+---+
println(rdd.collect().toBuffer)
ArrayBuffer(张三 12, 成吉思汗 20, 李四 33, 占城 45)
println(dataFrame.rdd.collect().toBuffer) 的输出
ArrayBuffer([张三,12], [成吉思汗,20], [李四,33], [占城,45])
println(dataFrame.javaRDD.collect())     //同下,输出结果一样,
println(dataFrame.toJavaRDD.collect())
[[张三,12], [成吉思汗,20], [李四,33], [占城,45]]

 

3 >RDD DataFrame DataSet数据集的理解

    参考:https://www.cnblogs.com/starwater/p/6841807.html

相同点:

 

1>全都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利
分布式弹性数据集:(spark的核心)弹性就是对于丢失的数据集,可以很快的重建
参考:https://www.cnblogs.com/han-guang-xue/p/10036225.html

2>三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算,
极端情况下,如果代码里面有创建、转换,但是后面没有在Action中使用对应的结果,在执行时会被直接跳过,如
val rdd=spark.sparkContext.parallelize(Seq(("a", 1), ("b", 1), ("a", 1)))
rdd.map{line=>
  println("运行")    //不会执行
  line._1
}
    
3>三者都会根据spark的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出
区别:
1> RDD一般和spark mlib同时使用  MLlib是Apache Spark的可扩展机器学习库。
2> RDD不包含源数据的信息  RDD是分布式的Java对象的集合  
 如,RDD[Person]是以Person为类型参数,但是,Person类的内部结构对于RDD而言却是不可知的,DataFrame是一种以RDD为基础的分布式数据集,也就是分布式的Row对象的集合(每个Row对象代表一行记录),提供了详细的结构信息,
  也就是我们经常说的模式(schema),Spark SQL可以清楚地知道该数据集中包含哪些列、每列的名称和类型。
 
3>
这里主要对比Dataset和DataFrame,因为Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同DataFrame也可以叫Dataset[Row],每一行的类型是Row,
不解析,每一行究竟有哪些字段,各个字段又是什么类型都无从得知,只能用上面提到的getAS方法或者共性中的第七条提到的模式匹配拿出特定字段而Dataset中,每一行是什么类型是不一定的,
在自定义了case class之后可以很自由的获得每一行的信息

可以看出,Dataset在需要访问列中的某个字段时是非常方便的,然而,如果要写一些适配性很强的函数时,如果使用Dataset,行的类型又不确定,可能是各种case class,无法实现适配,这时候用DataFrame即Dataset[Row]就能比较好的解决问题

 

 

 

 

posted @ 2018-11-30 17:19  韩若明瞳  阅读(1256)  评论(0编辑  收藏  举报