sparksql

spark 专栏收录该内容
8 篇文章 0 订阅

sparksql介绍

sparksql是spark用来处理结构化数据的一个模板,他提供了要给编程抽象叫做dataframe并且作为分布式sql查询引擎的作用

sparksql将sparksql转化为rdd,然后提交到集群执行,执行效率快

hive的应用其实是对应不会写java的开发人员,但是会写sql的数据库提供的是mr的一种简化

sparksql其实是对之前学习的sparkcore中rdd的一种简化,用sql的语言可以对rdd编程进行开发

spark是有处理上限的,10PB,超过这个范围还是要使用hive来处理的,hive的处理上限是100PB级别

sparksql优点

1.易整合

2.统一的数据访问方式

3.兼容hive

4.标准的数据连接

sparksql的操作方式

sparksql的数据抽象

对于sparkcore而言对数据的操作需要首先转换成rdd,对rdd可以使用各种算子进行处理,最终对数据进行统一操作,所以我们将rdd看做是对数据的封装(抽象)

对于sparksql而言,对数据进行操作的也需要进行转换,这里提供了两个新的抽象,分别是dataframe和dataset

RDD vs DataFrames vs DataSet

首先从版本上看

RDD

rdd是一个懒执行的不可变的可以支持functional(函数式编程)的并行数据集合.

rdd的最大好处就是简单,API的人性化程度很高

rdd的劣势是性能限制,它是一个jvm驻内存对象,这也就决定了存在gc的限制和数据增加时java序列化成本的升高

DataFrame

简单来说dataframe是rdd+schema的集合

什么是schema?

之前我们学过mysql数据库,在数据库中schema是数据库的组织和结构模式中包含了schema对象,可以是表(table)列(column)数据类型(data type),视图(view),存储过程(stored procedures),关系(relationships),主键(primary key)外键 (foreign key)等schema代表的就是一张表

与rdd类似,dataframe也是一个分布式的数据容器,然而dataframe更像传统数据库的二维表格,处理数据以外,还记录数据的结构信息,即schema,同时,与hive类似dataframe也支持嵌套数据类型(struct,array和map),从api易用性的角度上看,dataframeapi提供的是一套高层的关系操作,比函数式的rddapi更加友好,门槛更低,由于与r和pandas的dataframe类似,sparkdataframe很好的继承了传统单机数据分析的开发体验

dataframe是为数据提供了schema的视图,可以把他当做数据库中的一张表来对待,

dataframe也是懒执行的

性能比rdd要高,主要有两方面

定制化内存管理

优化执行计划

dataframe的劣势在于编译器缺少的类型安全检查,导致运行时出错,

dataframe只是知道字段但是不知道字段的类型,所以在执行这些操作的时候是没办法在编译的时候见擦汗是否类型失败的,比如你可以对一个string进行减法操作,在执行的时候才会报错,而dataset不仅仅知道字段而且世道字段类型,所以有更加严格的错误检查

dataset

是dataframeapi的一个扩展,是spark最新的数据抽象,

用户友好的api风格,既具有类型安全检查,也具有dataframe的查询优化特性,dataset支持编程解码器,当需要访问非堆上的数据式可以避免反序列化整个对象,提高了效率,

样例类被用来在dataset重定义数据的结构信息,样例类中每个属性的名称直接映射到dataset中定义的数据的结构信息,样例类中的每个属性的名称直接映射到dataset中的字段名称,

dataframe是dataset的特例,dataframe=dataset[row],所以可以通过as方法,将dataframe转换为dataset,row是一个类型,更car person这些类型一样,所有的表结构信息,我们都用row来表示

dataset是强类型,比如可以有dataset[car],dataset[person]

dataset[row]这个类似于我们学习的方形row就是泛型类型

三者的共性

1.rdd ,dataframe,dataset全都是spark平台下的分布式弹性数据库,为处理超大型数据提供便利

2.三者都有惰性机制,在进行创建,转换,如map方法时,不会立即执行,只有在遇到action如foreach是,三者才会开始遍历运算,极端情况下,如果代码里面有创建转换,,但是后面没有action中使用对应的结果,在执行时会被直接跳过

3.三者都会根据spark的内存情况自动缓存运算,这样即使数据量很大,也不用担心内存溢出

4.三者都有partition的概念

5.三者都有许多的共同函数,如filter,排序等

6.在对dataframe和dataset进行操作许多操作都需要这个包进行支持

7.dataframe和dataset均可使用模式匹配获取各个自读你的值和类型

三者的区别

rdd

rdd一般不和spark mlib同时使用

rdd不支持sparksql操作

dataframe

与rdd和dataset不同,dataframe每一行的类型固定为row,只有通过解析才能获取各个字段的值,每一列的值没法直接访问

dataframe与dataset一般不与spark mlib同时使用

dataframe与dataset均支持sparkslql的操作,比如select ,groupby之类,还能注册临时表/视窗,进行sql语句操作

dataframe与dateset支持一些特别翻遍的保存方式,比如保存成csv,可以带上表头,这样每一列的字段名一目了然

利用这样的保存方式,可以方便的获取字段名和列的对应,而且分隔符(delimiter)可以自由指定

dataset

dataset和dataframe拥有完全相同的成员函数,区别只是每一样的数据类型不同,

dataframe也可以叫dataset[row]每一行的类型是row,不解析,每一行究竟有哪些字段,各个字段优势什么类型都无从得知,只能用上面提到的getAS方法或者童星汇总的七条提出到的模式匹配拿出特定字段

而dataset中每一行是什么类型是不一定的,在自定义了case class之后可以很自由的获得每一行的信息

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

sparksql应用操作

在老版本中,saprksql提供了两种sql查询的起始点,一个叫sqlcontext,用于spark自己提供的sql查询,一个叫hivecontext,用于连接hive 的查询,sparksession提供 的是spark新的sql查询起始点,实际上是sqlContext和hivecontext的组合,所以在sqlcontext和hivecontext上可以用的api在sparksession上同样是可以使用的,sparksession内部封装了sparkcontext,所以计算实际上是由sparkcontext完成的

spark-shell基本操作

spark.read.json("/opt/software/spark-2.2.0-bin-hadoop2.7/examples/src/main/resources/people.json")
df.show()
df.filter($"age">21).show
df.createOrReplaceTempView("person")
spark.sql("select * from persons").show()
spark.sql("select * from persons where age > 21).show()

idea编写sparksql

maven pom

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-sql_2.11</artifactId>
    <version>${spark.version}</version>
</dependency>

sparksession的三种创建方式

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, SparkSession}
/**
  * SparkSession三种创建方式
  */
object SparkSQLDemo {
  def main(args: Array[String]): Unit = {
    /**
      * 创建SparkSession方式1
      * builder用于创建一个SparkSession。
      * appName设置App的名字
      * master设置运行模式(集群模式不用设置)
      * getOrCreate 进行创建
      */
    val sparks1=SparkSession.builder().appName("SparkSQLDemo").master("local").getOrCreate()
    /**
      * 创建SparkSession方式2
      * 先通过SparkConf创建配置对象
      * SetAppName设置应用的名字
      * SetMaster设置运行模式(集群模式不用设置)
      * 在通过SparkSession创建对象
      * 通过config传入conf配置对象来创建SparkSession
      * getOrCreate 进行创建
      */
    val conf=new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    val sparks2=SparkSession.builder().config(conf).getOrCreate()
    /**
      * 创建SparkSession方式3(操作hive)
      * uilder用于创建一个SparkSession。
      * appName设置App的名字
      * master设置运行模式(集群模式不用设置)
      * enableHiveSupport 开启hive操作
      * getOrCreate 进行创建
      */
      val sparkh = SparkSession.builder().appName("SparkSQLDemo").master("local).enableHiveSupport().getOrCreate()
    
    //关闭
    sparks1.stop()
    sparks2.stop()
    sparkh.stop()
  }
}
​

数据转换

rdd转换为dataframe

直接手动确定

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, SparkSession}
​
import org.apache.spark.rdd.RDD
/**
  * RDD--->DataFrame 直接手动确定
  */
object SparkSQLDemo {
  def main(args: Array[String]): Unit = {
    //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    //SQLContext要依赖SparkContext
    val sc = new SparkContext(conf)
    //从指定的地址创建RDD
    val lineRDD = sc.textFile("dir/people.txt").map(_.split(","))
    //这里是将数据转换为元组,数据量少可以使用这种方式
    val tuple: RDD[(String, Int)] = lineRDD.map(x => (x(0),x(1).trim().toInt))
    val spark = SparkSession.builder().config(conf).getOrCreate()
    //如果需要RDD于DataFrame之间操作,那么需要引用 import spark.implicits._ [spark不是包名,是SparkSession对象]
    import spark.implicits._
    val frame: DataFrame = tuple.toDF("name","age")
    frame.show()
    sc.stop();
    spark.stop();
  }
}

通过反射获取schema

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, SparkSession}
/**
  * RDD--->DataFrame 通过反射推断Schema
  */
object SparkSQLDemo {
  def main(args: Array[String]): Unit = {
    //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    //SQLContext要依赖SparkContext
    val sc = new SparkContext(conf)
    //从指定的地址创建RDD
    val lineRDD = sc.textFile("dir/people.txt").map(_.split(","))
    //除了这个方式之外我们还可以是用样例类的形式来做复杂的转换操作
    val tuple = lineRDD.map(x => People(x(0),x(1).trim().toInt));
    val spark = SparkSession.builder().config(conf).getOrCreate()
    import spark.implicits._
    //此时不需要使用指定列名会根据样例类中定义的属性来确定类名
    val frame: DataFrame = tuple.toDF
    frame.show()
    sc.stop()
  }
}
case class People(name:String,age:Int)

通过structType直接指定schema

import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
/**
  * RDD--->DataFrame 通过StructType直接指定Schema
  */
object SparkSQLDemo {
  def main(args: Array[String]): Unit = {
    //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    //创建SparkContext对象
    val sc = new SparkContext(conf)
    //创建SparkSession对象
    val spark = SparkSession.builder().config(conf).getOrCreate()
    //从指定的地址创建RDD
    val lineRDD = sc.textFile("dir/people.txt").map(_.split(","))
    //通过StructType直接指定每个字段的schema
    val schema = StructType(
      List(
        StructField("name", StringType, true),
        StructField("age", IntegerType, true)
      )
    )
    //将RDD映射到rowRDD
    val rowRDD = lineRDD.map(p => Row(p(0), p(1).trim.toInt))
    //将schema信息应用到rowRDD上
    val peopleDataFrame = spark.createDataFrame(rowRDD, schema)
    val frame: DataFrame = peopleDataFrame.toDF
    frame.show()
    sc.stop()
  }
}

dataframe转换成rdd

无论通过那种范式获取的dataframe都可以使用一个方法转换
val frameToRDD:RDD[Row] = frame.rdd
frameToRdd.foreache(x=>println(x.getString(0)+","+x.getInt(1)))

rdd转换为dataset

通过反射获取schema(样例类模式)

import org.apache.spark.rdd.RDD
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}
/**
  * RDD--->DataSet 通过反射获取Scheam
  */
object SparkSQLDemo {
  def main(args: Array[String]): Unit = {
    //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    //创建SparkContext对象
    val sc = new SparkContext(conf)
    //创建SparkSession对象
    val spark = SparkSession.builder().config(conf).getOrCreate()
    val value: RDD[String] = sc.textFile("dir/people.txt")
    import spark.implicits._
    val dataSet: Dataset[People] = value.map {
      x =>
        val para = x.split(",");
        People(para(0), para(1).trim().toInt);
    }.toDS()
    dataSet.show()
    sc.stop()
  }
}
case class People(name:String,age:Int)
​

dataset转换为rdd

//调用rdd方法
val dataSetTORDD:RDD[People] = dataSet.rdd
dataSetTORDD.foreach(x => println(x.name+","+x.age));

dataset转换为dataframe

//调用toDF方法,直接服用case class中定义的属性
val frame: DataFrame = dataSet.toDF()
frame.show()

dataframe转换为dataset

 val value: Dataset[People] = frame.as[People]
 case class People(name:String,age:Int)

总结:

sparksql支持两种类型分别为dataset和dataframe,这两种类型都支持从rdd转换为dataset或dataframe

rdd转dataframe有三种方法是

1,直接转换使用元素的模式存储再转换

2.使用样例类的模式匹配schema再转换(反射的方式)

3.structType直接指定schema再转换

rdd转dataset

使用样例类的模式匹配schema再转换

其余读取文件的方式可以直接获取对应的dataframe

dataset和dataframe之间的相互转换

dataset转换dataframe

调用toDF方法直接用case class中定义的属性

dataframe转换为dataset

调用as[对应样例类类名]

dataset对象或dataframe对象调用rdd方法就可以转换为rdd

数据操作方法

dsl语言风格

import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.{SparkConf, SparkContext}
​
object SparkSQL {
  def main(args:Array[String]):Unit = {
  //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    val spark = SparkSession.builder().config(conf).getOrCreate()
    val df: DataFrame = spark.read.json("dir/people.json")
    //DSL风格语法:
    df.show()
    import spark.implicits._
    // 打印Schema信息
    df.printSchema()
    df.select("name").show()
    df.select($"name", $"age" + 1).show()
    df.filter($"age" > 21).show()
    df.groupBy("age").count().show()
    spark.stop()
  }
}

sql风格

import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.{SparkConf, SparkContext}
​
object SparkSQL {
  def main(args:Array[String]):Unit = {
  //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    val spark = SparkSession.builder().config(conf).getOrCreate()
    val df: DataFrame = spark.read.json("dir/people.json")
    //SQL风格语法:
    //临时表是Session范围内的,Session退出后,表就失效了
    //一个SparkSession结束后,表自动删除
    df.createOrReplaceTempView("people")
    val sqlDF = spark.sql("SELECT * FROM people")
    sqlDF.show()
    //如果想应用范围内有效,可以使用全局表。注意使用全局表时需要全路径访问,如:global_temp.people
    //应用级别内可以访问,一个SparkContext结束后,表自动删除 一个SparkContext可以多次创建SparkSession
    //使用的比较少
    df.createGlobalTempView("people")
   //创建名后需要必须添加global_temp才可以
    spark.sql("SELECT * FROM global_temp.people").show()
    spark.newSession().sql("SELECT * FROM global_temp.people").show()
    spark.stop()
  }
}

需要打包上传集群,可以在集群中使用这个jar包

在安装spark目录下进入到bin目录执行spark-submit

/usr/local/spark/bin/spark-submit \

--class 需要执行的类的全限定名(从包开始到类名结束) \

--master 指定主节点 \

上传jar所在的位置 \

数据输入路径 \

数据输出路径 -->没有可以不写

sparksql自定义函数

udf函数

用户自定义函数

import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.{SparkConf}
// 需求:实现字符串拼接
object SparkSQL {
  def main(args:Array[String]):Unit = {
  //创建SparkConf()并设置App名称
    val conf = new SparkConf().setAppName("SparkSQLDemo").setMaster("local")
    val spark = SparkSession.builder().config(conf).getOrCreate()
    val df: DataFrame = spark.read.json("dir/people.json")
    //注册函数,在整个应用中可以使用
    val addName = spark.udf.register("addName", (x: String) => "Name:" + x)
    df.createOrReplaceTempView("people")
    spark.sql("Select addName(name), age from people").show()
    spark.stop()
  }
}

udaf函数

用户自定义聚合函数

udaf函数支持dataframe(弱类型)

通过继承userdefinedaggregateFunction来实现用户自定义聚合函数,

弱类型指的是在编译阶段是无法确定数据类型的,而是在运行阶段才能创建类型

udaf函数支持dataset(强类型)

通过继承aggregator来实现强类型自定义聚合函数,

在编译阶段就确定了数据类型

开窗函数

说明:
rank()跳跃函数,有两个第二名时后面跟着的是第四名
dense_rank()连续函数,有两个第二名后面仍然跟着第三名
over()开窗函数:
    在使用聚合函数后,会将多行变成一行,而开窗函数是将一行变成多行
    而且在使用聚合函数后,如果要显示其他的列必须将列加入到groupby中
    而使用开窗函数后,可以不适用groupby,直接将所有信息显示出来,
    开窗函数适用于在每行的最后一列添加聚合函数的结果
常用开窗函数:
    1.为每条数据显示聚合信息,(聚合函数() over())
    2.为每条数据提供分组的聚合函数结果(聚合函数() over (partition by 字段) as 别名)
        --按照字段分组,分组后进行计算
    3.与排名函数一起使用,(row number() over(over by 字段名)as 别名)
        1.row_number() over(partition by ... order by)
        2.rank() over(partition by .. order by ...)
        3.dense_rank() over(partition by ... order by ...)
        4.count() over(partition by ... order by ...)
        5.max()
        6.min()
        7.avg()
        8.first_value()
        9.last_value()
        10.sum()
        11.lag()
        12.lead()
lag和lead获取的结果集中,按一定排序所排列的当前行的上下相邻若干个offset的某个行的某个列(不用结果集的自关联)
lad,lead分别是向前,向后
lag和lead有三个参数第一个参数是列名,第二个参数是偏移的offset,第三个 参数是超出记录窗口时的默认值
​

集成hive

apachehive是hadoop上的sql引擎,sparksql编译时可以包含hive支持,也可以不包含,包含hive支持的spark sql可以支持hive 表访问,udf(用户自定义函数)以及hive查询语言(hiveql/hql)等,需要强调的是如果在spark中包含hive的库,并不需要事先安装hive

一般来说,最好还是在编译sparksql时引入 hive支持,这样就可以使用这些特性了

使用内置hive

ps:需要注意内置hive是非常容易出现问题的
1.先启动集群/opt/software/spark-2.2.0-bin-hadoop2.7/sbin/start-all.sh
2.进入到spark-shell模式/opt/software/spark-2.2.0-bin-hadoop2.7/bin/spark-shell --master spark://hadoop01:7077
3.在spark-shell下操作hive
spark.sql("show tables").show 查询所有hive的表
spark.sql("CREATE TABLE IF NOT EXISTS src (key INT,value STRING)") 创建表
spark.sql("LOAD DATA LOCAL INPATH '/opt/software/spark-2.2.0-bin-hadoop2.7/examples/src/main/resources/kv1.txt' INTO TABLE src")  添加数据
spark.sql("SELECT * FROM src").show 查询表中数据
会出现一个问题FileNotFoundException 没有找到文件
通过在主节点和从节点查询可以发现,主节点存在spark-warehouse目录 目录中是存在数据的
但是在从节点中没有这个文件夹,所以此时将文件夹分发到从节点
scp -r ./spark-warehouse/ root@hadoop02:$PWD 
再次执行查询
ps:这样表面看查询是没什么问题了,但是实际问题在于是讲master节点上的数据分发到从节点上的,那么不可能说每次操作有了数据都执行拷贝操作,所以此时就需要使用HDFS来进行存储数据了
所以先将所有从节点上的spark-warehouse删除掉
删除后将主节点上的spark-warehouse和metastor_db删除掉
然后在启动集群的时候添加一个命令
 --conf spark.sql.warehouse.dir=hdfs://hadoop01:8020/spark_warehouse
 此方法只做一次启动即可 后续再启动集群的时候就无需添加这个命了 因为记录在metastore_db中了
 ps:spark-sql中可以直接使用SQL语句操作

集成外部hive

将hive-site.xml软连接到spark安装目录下的conf目录下[主节点有即可]
ln -s /usr/local/hive/conf/hive-site.xml /usr/local/spark/conf/hive-site.xml
​
打开sparkshell注意带上hive元数据库的jdbc客户端
将mysql驱动jar包拷贝到spark的bin目录下
./spark-shell --master spark://leetom:7077 --jars mysql-connector-java-5.1.36.jar
​
做完外部hive连接需要注意,因为hive-site.xml文件是在spark的conf目录下,若直接启动spark-shell无论是单机版还是几区都会出现报错error creating tarnsactional connection factory 原因在于启动时会加载hive-site.xml文件,所以必须加载jar路径,为了以后使用建议删除软链接,需要的时候再做外部hive连接,
rm-rf 软链接

总结:

若要把sparksql连接到一个部署好的hive上,你必须把hive-site.xml复制到spark的配置文件目录中($SPARK_HOME/conf),即使没有部署好hive,sparksql也可以运行,需要注意的是,如果没有部署好hive,sparksql会在当前的工作目录中创建自己的hive元数据仓库,叫做metastore_db,此外,如果尝试使用hiveql中的create table(并非create external table)语句来创建表,这些表会被凡在你默认的文件系统中,/user/hive/warehouse目录中(如果你的classpath中有配好的hdfs-site.xml,默认的文件系统就是hdfs,否则就是本地文件系统

通过代码操作

需要有hadoop本地环境

import org.apache.spark.sql.{Row, SparkSession}
object HiveCode {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession
      .builder()
      .appName("HiveCode")
      .config("spark.sql.warehouse.dir", "D:\\spark-warehouse")
      .master("local[*]")
      .enableHiveSupport()
      .getOrCreate()
    import spark.implicits._
    import spark.sql
   // sql("CREATE TABLE IF NOT EXISTS src_1 (key INT, value STRING)")
    sql("LOAD DATA LOCAL INPATH  'dir/kv1.txt' INTO TABLE src_1")
    sql("SELECT * FROM src_1").show()
    sql("SELECT COUNT(*) FROM src_1").show()
    val sqlDF = sql("SELECT key, value FROM src_1 WHERE key < 10 ORDER BY key")
    sqlDF.as("mixing").show()
    val recordsDF = spark.createDataFrame((1 to 100).map(i => Record(i, s"val_$i")))
    recordsDF.createOrReplaceTempView("records")
    sql("SELECT * FROM records r JOIN src_1 s ON r.key = s.key").show()
  }
}
case class Record(key: Int, value: String)
如果本地出现ErrorWhileinstantiating
org.apache.spark.sql.hive.HiveSessionStateBuilder和权限异常问题
在cmd命令进入到d:/hadoop2.7.6/bin目录执行命令
winutils.exe chmod 777 /tmp/hive

连接服务器hive

需要添加hive-site.xml hdfs-site.xml core-site.xml

import java.io.File
​
import org.apache.spark.sql.{Row, SparkSession}
​
object HiveCode {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession
      .builder()
      .appName("HiveCode")
      .config("spark.sql.warehouse.dir", "hdfs://hadoop01:8020/spark_warehouse")
      .master("spark://hadoop01:7077")
      .enableHiveSupport()
      .getOrCreate()
    import spark.implicits._
    import spark.sql
    //sql("CREATE TABLE IF NOT EXISTS src_1 (key INT, value STRING)")
   // sql("LOAD DATA LOCAL INPATH 'dir/kv1.txt' INTO TABLE src_1")
    sql("SELECT * FROM src_1").show()
  sql("SELECT COUNT(*) FROM src_1").show()
   val sqlDF = sql("SELECT key, value FROM src_1 WHERE key < 10 ORDER BY key")
   sqlDF.as("mixing").show()
    val recordsDF = spark.createDataFrame((1 to 100).map(i => Record(i, s"val_$i")))
    recordsDF.createOrReplaceTempView("records")
    sql("SELECT * FROM records r JOIN src_1 s ON r.key = s.key").show()
  }
}
case class Record(key: Int, value: String)

sparksql的输入和输出

spark的输入

写法一:

SparkSession对象.read.json("路径")

SparkSession对象.read.jdbc("路径")

SparkSession对象.read.csv("路径")

SparkSession对象.read. parquet("路径") Parquet格式经常在Hadoop生态圈中被使用,它也支持Spark SQL的全部数据型

SparkSession对象.read.orc("路径")

SparkSession对象.read.table("路径")

SparkSession对象.read.text("路径")

SparkSession对象.read. textFile("路径")

写法2:

SparkSession对象.read.format("json").load("路径")

ps:若不执行format默认是parquet格式

sparksql输出

写法一:

DataFrame或DataSet对象.write.json("路径")

DataFrame或DataSet对象.write.jdbc("路径")

DataFrame或DataSet对象.write.csv("路径")

DataFrame或DataSet对象.write.parquet("路径")

DataFrame或DataSet对象.write.orc("路径")

DataFrame或DataSet对象.write.table("路径")

DataFrame或DataSet对象.write.text("路径")

写法二:

DataFrame或DataSet对象.write.fomat("jdbc").中间可能其他的参数.save()

ps:典型的是saveMode模式 即 mode方法

scala/javaany languagemeaning
SaveMode.ErrorIfExists(default)"error" (default)如果文件存在,则报错
SaveMode.Append"append"追加
SaveMode.OverWrite"overwrite"覆写
SaveMode.Ignore"ignore"数据存在,则忽略

若不执行format默认是parquet格式

jdbc操作

从mysql中将数据获取

maven.pom

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
import java.util.Properties
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession
​
object SparkSQLAndMySQL {
  def main(args: Array[String]): Unit = {
     val spark = SparkSession.builder().appName("SparkSQLAndMySQL").master("local").getOrCreate()
     //读取方式一
    val connectionProperties = new Properties()
    connectionProperties.put("user", "root")
    connectionProperties.put("password", "123456")
    val jdbcDF = spark.read.jdbc("jdbc:mysql://localhost:3306/db1", "t_student",connectionProperties)
    jdbcDF.show();
​
    //方式二
    val jdbcDF2 = spark.read.format("jdbc")
.option("url","jdbc:mysql://localhost:3306/db1").option("dbtable","t_student").option("user","root").option("password","123456").load()
    jdbcDF2.show()
​
    spark.stop()
  }
}

将数据输出到mysql中

import java.util.Properties
import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}
​
object SparkSQLAndMySQL {
  def main(args: Array[String]): Unit = {
     val spark = SparkSession.builder()
      .appName("SparkSQLAndMySQL").master("local")
      .getOrCreate()
    //读取数据
     val frame: DataFrame = spark.read.json("dir/employees.json")
    //输出方法一
    val connectionProperties = new Properties()
    connectionProperties.put("user", "root")
    connectionProperties.put("password", "123456")
    //表可以不存在,通过读取的数据可以直接生成表
    frame.write.jdbc("jdbc:mysql://localhost:3306/db1","employees",connectionProperties)
​
    //输出方式二
    frame.write.format("jdbc")
      .option("url", "jdbc:mysql://localhost:3306/db1")
      .option("dbtable", "employees1")
      .option("user", "root")
      .option("password", "123456")
      .save()
   //输出方式三 执行创建表的列名和数据类型 数据类型不能大写
    frame.write
      .option("createTableColumnTypes", "name varchar(200),salary int")
      .jdbc("jdbc:mysql://localhost:3306/db1", "employees2", connectionProperties)
    spark.stop()
  }
}

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值