spark sql 技术说明与常见的操作(其一)

spark sql 性能技术简介:
1,内存列存储(in-memory columnar storage):Spark sql 的数据,不是使用 java 对象的方式来进行存储,而是使用了面向列的方式进行存储。每一列作为一个数据存储的单位,从而大大的优化了内存的使用效率,减少了对内存的消耗,也就避免了gc的大量数据的性能消耗
2,字节码生成技术(byte-core generation):spark sql 在其catalyst模块增加了codegen模块,对于SQL语句的计算表达式 select num +num from t这种sql,就可以使用动态字节码技术
3,Scala 代码的优化:对于scala代码编写中,可能会造成性能较大开销的地方,自己重写或者更改逻辑,使用更加复杂的方式,来获取性能提升
DataFrame:以列的形式组织的,分布式的数据集合.它和关系型数据库中的表类似,但是做了底层的优化.DataFrame可以通过很多源来进行构建,包括:结构化数据文件,Hive之中的表,外部的关系型数据库,RDD等
spark sql 常见的操作:
1,处理的文件 json_load.json (并不是json格式,可以根据hive load文件理解)
    {"name": "小明","age": 13,"from":"heman"},
    {"name": "小Q","age": 11,"from":"shanghai"},
    {"name": "小G","age": 14,"from":"qingzang"}
   2,scala 代码示意
package day02
import org.apache.spark.sql.SQLContext
import org.apache.spark.{SparkConf, SparkContext}
object sparksql {
  def main(args: Array[String]){
    //创建 DataFrame
    val conf =new SparkConf().setAppName("SQL")
    val sc =new SparkContext(conf)
    val sqlContext =new SQLContext(sc)
    conf.set("spark.testing.memory", "2147480000")
    //创建的 DataFrame 可以理解一张表
    val df = sqlContext.read.json("hdfs://master:9000/json_load.json")
    // 打印 DataFrame所有数据
    df.show()
    /*
    |  小明|       14|
    |  小Q|       12|
    |  小G|       15|
    * */
    // 打印 DataFrame元数据(Scheme)
    df.printSchema()
    /*
    root
     |-- age: long (nullable = true)
     |-- from: string (nullable = true)
     |-- name: string (nullable = true)
    * */
    // 查询某一列的所有数据
    df.select("name").show()
    /*
    *  小明|
      |  小Q|
      |  小G|
    * */
    // 查询某几列数据 并且进行计算
    df.select(df("name"),df("age")+1).show()
    /*
    +----+---------+
    |name|(age + 1)|
    +----+---------+
    |  小明|       14|
    |  小Q|       12|
    |  小G|       15|
    +----+---------+
    * */
    // 对于某列的值进行过滤
    df.filter(df("age")>18).show()
    // 某列的值进行 分组 然后尽心聚合
    df.groupBy("age").count().show()
    /*
    | 11|    1|
    | 13|    1|
    | 14|    1|
    */}
}
RDD转换 DataFrame 的两种方式:
1,使用反射来推断包含了特定数据的RDD,此时是已经知道RDD的元数据
2,通过编程接口来创建 DataFrame(运行的过程才知道元数据),可以再程序运行的时候创建一份元数据,将其动态添加到已经存在的RDD元数据之中
使用反射创建RDD
package day02
import org.apache.spark.sql.SQLContext
import org.apache.spark.{SparkConf, SparkContext}
object RddToDataFrame extends App {
    val conf = new SparkConf().setAppName("Frame").setMaster("local")
    val sc = new SparkContext(conf)
    val sqlcontext = new SQLContext(sc)
    // scala 使用反射进行 rdd 转换 DataFrame需要使用隐式转换
    import sqlcontext.implicits._
    //相当于表的schema
    case class Students(id:Int,name:String,age:Int)
    // 元素为 case class 的RDD
    // spark sql 会通过反射读取传递给 case class 的参数的名称,然后将其作为列明
    val students =sc.textFile("/student.txt")
      .map(line => line.split(","))
      //将RDD和case class关联
      .map(arr =>Students(arr(0).trim().toInt,arr(1),arr(2).trim().toInt))
  //将RDD转换成DataFrame
    val studentDF =students.toDF()
    studentDF.registerTempTable("students")
    val teenageDF = sqlcontext.sql("select * from students where age<18")
    val teenagerRDD = teenageDF.rdd
    teenagerRDD.map{row => Students(row(0).toString.toInt,row(1).toString,row(2).toString.toInt)}
    .collect()
    .foreach(stu=>println(stu.id+":"+stu.name+":"+stu.age))
    // 使用 row 的getAs() 方法来获取指定的列名的列
    teenagerRDD.map{row => Students(row.getAs[Int]("id"),row.getAs("name"),row.getAs("age"))}
    .collect()
    .foreach(stu=>println(stu.id+":"+stu.name+":"+stu.age))
    // 通过 row 的 getValuesMap 方法获取指定的几列的值,返回的是 map
    val t = teenagerRDD.map(row=>{
        val map = row.getValuesMap[Any](Array("id","name","age"));
        Students(map("id").toString().toInt,map("name").toString(),map("age").toString().toInt)
      })
      t.collect()
      .foreach(stu=>println(stu.id+":"+stu.name+":"+stu.age))
}
通过编程接口来创建 DataFrame
package day02
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{Row, SQLContext}
import org.apache.spark.sql.types.{StructType,StructField,StringType,IntegerType}
object RDDtoDataframe_Programe extends App {
      val conf = new SparkConf().setMaster("local[*]")
        .setAppName("RDD")
      val sc = new SparkContext(conf)
      val sqlContext = new SQLContext(sc)
      // 构造元素为 Row的普通 RDD
      val studentsRdd = sc.textFile("/student.txt",1)
        .map(
          line => Row(  // Row 里面取出的数据是 string类型的数据
            line.split(",")(0).toInt,
            line.split(",")(1).toString,line.split(",")(2).toInt
          ))
      // 以编程的方式构造元数据, id name age 字段,
      // 可能是在程序运行的过程之中动态从数据库读取的,或者配置文件之中
      val structType = StructType(Array(
        StructField("id",IntegerType,true),
        StructField("name",StringType,true),
        StructField("age",IntegerType,true)))
      // 第三步进行 RDD 到 DataFrame的转换
      val studentsDF = sqlContext.createDataFrame(studentsRdd,structType)
      studentsDF.registerTempTable("students")
      val teenagerDF = sqlContext.sql("select * from students where id<18")
      val teenagerRdd = teenagerDF.rdd.collect().foreach(row =>println(row))
}
spark 的 load与save操作:
1,对于 spark sql 的DataFrame 来说,无论从什么数据源创建的 DataFrame,都有共同的load 与 save操作.load操作主要是加载数据,创建出 DataFrame,save操作主要是讲 DataFrame 保存到文件(列存储)之中.
2,可以手动指定来操作数据源类型,指定load 数据源格式与save格式,可以使用这个功能进行数据源类型的转换
3,save操作可以指定 SaveMode 目标位置文件存在,如何进行处理
package day02
import org.apache.spark.sql.{SQLContext, SaveMode}
import org.apache.spark.{SparkConf, SparkContext}
object GenderLoadSave {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("LoadAndSave")
      .setMaster("local[*]")
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc)
    // 加载文件 创建出DataFrame
    val UserDf = sqlContext.read.load("hdfs://master:9000/users.parquet")
    // 保存为到文件夹之中   SaveMode.ErrorIfExists 表明文件存在就抛出异常
    UserDf.write.mode(SaveMode.ErrorIfExists)
      .save("hdfs://master:9000/users_new_parquet.scala")
    // 手动指定数据源格式 load数据源格式与 save数据源格式
    val peopleDF = sqlContext.read.format("json").load("hdfs://master:9000/people.json")
    //SaveMode.Append 表明如果目标位置已经存在文件,那么就追加进去
    peopleDF.select("name").write.mode(SaveMode.Append)
      .format("parquet").
      save("hdfs://master:9000/people_json_parquet")
  }}

 

转载于:https://www.cnblogs.com/shi-qi/articles/10626551.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值