Spark SQL

特性

  1. 易整合
  2. 统一的数据访问方式
  3. 兼容hive
  4. 标准的数据链接

DataFrame和DataSet,并且作为分布式SQL查询引擎的作用

SparkSession创建

在老的版本中,SparkSQL提供两种SQL查询起始点:一个叫SQLContext,用于Spark自己提供的SQL查询;一个叫HiveContext,用于连接Hive的查询。

SparkSession是Spark最新的SQL查询起始点(2.0.0版本之后),实质上是SQLContext和HiveContext的组合,所以在SQLContext和HiveContext上可用的API在SparkSession上同样是可以使用的。SparkSession内部封装了sparkContext,所以计算实际上是由sparkContext完成的

val builder = SparkSession.builder().master("local")
    val session: SparkSession = builder.getOrCreate()
    session.sparkContext.getConf.setMaster("local")

 DataFrame

DataFrame是一个分布式数据容器,然而DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema。同时,与Hive类似,DataFrame也支持嵌套数据类型(struct、array和map)。从API易用性的角度上看,DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好,门槛更低

DataFrame创建 

PS: 下面为操作的数据源(可以自己造数据测试)

[{"name":"朱元璋","age":41},{"name":"朱允文","age":22},{"name":"朱棣","age":43},{"name":"朱高炽","age":47},{"name":"朱瞻基","age":28},{"name":"朱祁镇","age":9},{"name":"朱祁钰","age":22},{"name":"朱见深","age":18},{"name":"朱佑橖","age":18},{"name":"朱厚照","age":15},{"name":"朱厚熜","age":18},{"name":"朱翊钧","age":10},{"name":"朱常洛","age":39},{"name":"朱由校","age":16},{"name":"朱由检","age":18}]
//可以使用绝对路径,也可以使用相对路径
    val rdd: sql.DataFrame = session.read.option("multiLine", true)//多行载入
      .json("scala-demo\\src\\main\\scala\\com\\example\\scala\\rdd\\emperor.json")

展示数据及schema 

rdd.show()
    rdd.printSchema()

创建临时表 

注意:临时表是Session范围内的,Session退出后,表就失效了

//临时表创建
    rdd.createOrReplaceTempView("emperor")

创建全局表 

注意:如果想应用范围内有效,可以使用全局表。使用全局表时需要全路径访问,如:global_temp.people

//全局表创建
    rdd.createGlobalTempView("emperor")

 sql编写(常用)

// 默认不加任何前缀
    //    val rdd = session.sql("select name,age from emperor")
    // 增加临时前缀
    //    val rdd = session.sql("select name,age from tem.emperor")
    // 增加全局前缀
    val sql1 = session.sql("select name,age from global_temp.emperor")
    // 直接进行sql运算
    val sql2 = session.sql("select name,age+1 as age from global_temp.emperor")
    // 分组sql
    val sql3 = session.sql("select age ,count(1) from global_temp.emperor group by age")

 api接口(较常用)

def testSqlApi(session: SparkSession) = {
    //需要在方法中导入该扩展功能才能使用$"xxx"的方式
    import session.implicits._
    val df = session.read.option("multiLine", true).json("scala-demo\\src\\main\\scala\\com\\example\\scala\\rdd\\emperor.json")
    //df.printSchema()
    println("1.1: 指定列字段名称select()方式")
    df.select("name", "age").show()

    println("1.2:指定列字段名称selectExpr()方式")
    df.selectExpr("name", "age+1").show()
    // 1.6.0之前的写法
    println("1.3:指定列字段名称df('xxx')方式")
    df.select(df("name"), df("age") + 1).show()
    println("1.4:指定列字段名称$'xxx'方式")
    // 2.1.0版本之后的写法
    df.select($"name", $"age" + 1).show()
    println("2.指定列字段名称")
    df.filter("age>25").show()
    df.filter($"age" > 25).show()
    println("3.分组求个数")
    df.groupBy("age").count().show()
    println("4.指定字段的运算")
  }

执行查询结果 

println("1.指定列字段查询结构: ")
    sql1.show()
    println("2.字段运算查询结果: ")
    sql2.show()
    println("3.分组查询结果")
    sql3.show()

结果输出 (sql)

 

Spark SQL编程初级实践总结 spark sql开发_DataFrame

Spark SQL编程初级实践总结 spark sql开发_Spark_02

Spark SQL编程初级实践总结 spark sql开发_sql_03

 结果输出(api) 

Spark SQL编程初级实践总结 spark sql开发_DataFrame_04

 RDD转换成DataFrame

PS:如果需要RDD与DF或者DS之间操作需要引入包

        

   import session.implicits._

源文件

ming.txt

朱元璋 41
朱允文 22
朱棣 43
朱高炽 47
朱瞻基 28
朱祁镇 9
朱祁钰 22
朱见深 18
朱佑橖 18
朱厚照 15
朱厚熜 18
朱翊钧 10
朱常洛 39
朱由校 16
朱由检 18
def testTransfer(session: SparkSession) = {
    import session.implicits._
    val pRdd = session.sparkContext.textFile("D:\\Java\\workspace\\study\\scala-demo\\src\\main\\scala\\com\\example\\scala\\rdd\\ming.txt")
    println("rdd转换成df")
    val eRdd: sql.DataFrame = pRdd.map(x => {
      val emperor = x.split(" ")
      (emperor(0), emperor(1))
    }).toDF("name", "age")
    eRdd.createGlobalTempView("emperor")
    session.sql("select name,age from global_temp.emperor where age > 40").show()
  }
rdd转换成df
+----+---+
|name|age|
+----+---+
| 朱元璋| 41|
|  朱棣| 43|
| 朱高炽| 47|
+----+---+

DataFrame转换成 RDD

DataFrame对象中内置属性rdd,可以直接通过该属性获取RDD

val rdd = eRdd.rdd
    println("df转换成rdd")
    rdd.collect().foreach(x => print(x) + ", ")
## 输出
[朱元璋,41][朱允文,22][朱棣,43][朱高炽,47][朱瞻基,28][朱祁镇,9][朱祁钰,22][朱见深,18][朱佑橖,18][朱厚照,15][朱厚熜,18][朱翊钧,10][朱常洛,39][朱由校,16][朱由检,18]