spark学习8:spark SQL

1.spark SQL是什么?

spark SQL类似 hive 的功能。

hive 是把SQL转译成 查询hadoop的语法,

而spark SQL是把 SQL转译成 查询spark的语法。

并且,spark SQL的前身 shark(也叫hive on spark) 就是借鉴的hive的  前几个步骤,即除了最后的转译成 查询spark的代码,之前都借鉴了。

2.为什么用spark SQL?

2.1关系型数据库在大数据时代的不足

根源还是因为关系型数据库不能满足目前数据存读需求,

大数据时代,90%的数据都是非结构化和半结构化的。

1.需要一个工具能够满足, 结构化和非结构化的数据处理需求。

2.关系型数据库,只能做一些简单的聚合操作(求和、平均值等),

  无法满足一些高级分析需求,比如 机器学习、图计算等。

spark SQL的优势:

1.有个数据抽象 叫dataframe,可以把结构化和 非结构化的数据融合起来。

2.可以应用于处理高级分析 机器算法、图形计算等。MLlib 的机器学习算法中,底层的数据结构就是是sparkSQL的 dataframe

2.2shark的缺陷

spark SQL的前身 shark(也叫hive on spark) 照搬hive的  前几个步骤,

存在2个致命问题,

1. 执行计划优化环节,无法添加新的优化策略

hive 是专门把SQL转为对hadoop的查询 ,即MapReduce程序,

对spark的程序的优化并不好。

2.spark是线程级的程序,而hadoop是进程级的程序。

导致shark 一开始就存在 线程安全问题。

所以,sparkSQL除了引用 hive 中第一个parase模块 (该模块是把SQL转为语法树)外,其他模块,查询计划、查询优化....完全面向spark应用自己研发。

3.spark SQL的使用

3.1 spark dataframe

sparkSQL新增了一个 数据抽象,dataframe

dataframe 相较RDD 多了一个结构化存储。

 3.2 RDD 和 sparkSQL 的dataframe 的区别

传统的RDD是将数据存储为一个个对象,然后数据的值相当于对象的一个属性。

eg:RDD 需要找到张三的刷牙杯,第一步,先找到张三 这个对象,然后再从张三对象中 取刷牙杯的属性。

dataframe 是相当于 把RDD做了结构化的存储。

3.3创建 dataframe 对象

3.3.1 就像创建RDD一样,需要先创建一个sparkSession 对象

ps:spark-shell 环境中会 自动生成两个对象, sparkContext对象 :sc 和 sparkSession对象:spark

但是如果在 自己的编程环境中,需要手动生成 sparkSession对象

 ps:在idea中 ,如果没有sparkSQL的依赖,需要现在pom.xml 中添加依赖,

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-sql_2.12</artifactId>
    <version>3.0.3</version>
</dependency>

详细版看下边文章:

在idea中pom.xml添加sparkSQL依赖_hzp666的博客-CSDN博客

ps: 如果遇到报错:

java: 程序包org.junit.jupiter.api不存在

需要在pom.xml中添加 依赖,

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <scope>test</scope>
</dependency>

如果添加依赖,报找不到该依赖,看下边文章

idea 添加dependency 依赖,报错找不到依赖_hzp666的博客-CSDN博客

报错:Exception in thread "main" java.lang.NoSuchMethodError: org.apache.spark.ContextCleaner.registerSparkListenerForC

看下边这个文章

Exception in thread “main“ java.lang.NoSuchMethodError: org.apache.spark.ContextCleaner.registerSpar_hzp666的博客-CSDN博客

3.3.2创建dataframe

1.

2.导入隐式转换包,

3.4读取数据文件

读取json 数据:

读取parquet文件

 读取csv 文件:

eg1: 读取一个json文件

在idea中读取json文件,代码执行如下

import org.apache.spark.sql.{DataFrame, SparkSession}

object sparkSQLTestCreate {
  def main(args: Array[String]): Unit = {

//create spark's Commander
    val spark = new SparkSession.Builder().master("local").appName("sparkSQLTest").getOrCreate()

    //for Implicit conversion
    import spark.implicits._
    
    //read local json file
    val df: DataFrame = spark.read.json("file:///D:/software/spark/spark-3.0.3-bin-hadoop2/spark-3.0.3-bin-hadoop2.7/examples/src/main/resources/people.json")

    //show the dataframe
    df.show()
  }

}

在idea中读取txt文件,代码执行如下

import org.apache.spark.sql._
object sparkSQLTestFile {
  def main(args: Array[String]): Unit = {

    //create spark's commander
    val spark = new SparkSession.Builder().master("local").appName("sparkSQLTestFile").getOrCreate()

    //for implicit transfer
    import spark.implicits._

    //read file
    val df: DataFrame = spark.read.text("file:///D:/software/spark/spark-3.0.3-bin-hadoop2/spark-3.0.3-bin-hadoop2.7/examples/src/main" +
      "/resources/people.txt")

    //show
    df.show()


  }
}

读取其他的文件 只要修改下,spark.read. parquet / csv / text 即可

读取文件也可以先生成RDD,再转成dataframe。

有两种方法:

第一种:利用反射机制 (伴生类),

适用于表结构固定,字段明确的RDD数据源。

import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SparkSession}


object sparkSQLTestRDDToDF {

  //define a Associated Class
  case class Person(name :String, age:Int)


  def main(args: Array[String]): Unit = {

    //create spark commander
    val spark = new SparkSession.Builder().master("local").appName("sparkSQL").getOrCreate()

    //read
    val rddTxt: RDD[String] = spark.sparkContext.textFile("file:///D:/software/spark/spark-3.0.3-bin-hadoop2/spark-3.0.3-bin" +
      "-hadoop2.7/examples" +
      "/src" +
      "/main" +
      "/resources/people.txt")

    //for transfer
    import spark.implicits._

    //split and transfer to df
    val personDF: DataFrame = rddTxt.map(_.split(",")).map(attribute => Person(attribute(0),attribute(1).trim
      .toInt)).toDF()

    //create a table, and set the table name

    personDF.createOrReplaceTempView("Person")

    //select
    val newPersonRDD = spark.sql("select * from Person where age > 20")

    //show
    newPersonRDD.foreach(println(_))

  }

}

第二种,编程方式定义RDD转为DF

适用于 表结构不固定,字段是动态获取的。

 编程方式实现RDD转换 需要三步;

1. 生成表头

2.得到表中的数据

3.表头与表中数据结合

import org.apache.spark.sql.SparkSession
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.DataFrame

//for table header
import org.apache.spark.sql.types._

//for table data rows
import org.apache.spark.sql.Row

object sparkSQLTestRDDToDF2 {

  def main(args: Array[String]): Unit = {
    //create spark commander
    val spark = new SparkSession.Builder().master("local").appName("sparkSQLTest").getOrCreate()

    /*create table schema*/

    //define table files
    val fields = Array(StructField("name", StringType, true), StructField("age", IntegerType, true))

    //generate table schema
    val schema = StructType(fields)

    /*get row data*/

    //read
    val peopleRDD = spark.sparkContext.textFile("file:///D:/software/spark/spark-3.0.3-bin-hadoop2/spark-3.0.3-bin-hadoop2.7/examples/src/main/resources/people.txt")

    //clean and create row
    val dataRDD: RDD[Row] = peopleRDD.map(_.split(",")).map(attribute => Row(attribute(0), attribute(1).trim.toInt))

    /*create data table*/
    //merge
    val peopleDF: DataFrame = spark.createDataFrame(dataRDD, schema)

    //create temp table
    peopleDF.createOrReplaceTempView("people")

    val selectData = spark.sql("select * from people")

    //show
    //for implicit transfer
    import spark.implicits._
    selectData.map(x => "name:"+x(0)+" --"+"age:"+x(1)).show()
    
  }
}

ps:  在指定字段类型时候,注意导入的包是下边这个

 

3.5 写入文件

3.5.1写入json

可以直接用RDD方式 保存文件


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值