Spark SQL 7.使用示例


1. 设置

# 设置动态分区
set hive.exec.dynamic.partition.mode=nonstrict; 
# 设置结果压缩
set hive.exec.compress.output=true;
  • rdd.toDF() 找不到的问题,需要导入
val session = SparkSession.builder().getOrCreate();

// 导入隐式转换
import session.implicits._

2. 交易记录查询示例:从RDD创建DataFrame并进行SQL查询

// 定义交易记录样例类,包含账户号和交易金额两个字段
scala> case class Trans(accNo:String,tranAmount:Double)

defined class Trans
 
// 定义转换函数:将字符串数组转换为Trans对象
// trans(0) 是账户号,trans(1).trim.toDouble 是交易金额(去除空格后转为Double类型)
scala> def toTrans = (trans: Seq[String]) => Trans(trans(0),trans(1).trim.toDouble)

toTrans: Seq[String] => Trans

// 创建交易记录数据数组,每条记录格式为"账户号,交易金额"
scala> val acTransList = Array("HA1001,1000","HA1002,2000","HA1003,3000","HA1004,400","HA1005,1000")

acTransList: Array[String] = Array(HA1001,1000, HA1002,2000, HA1003,3000, HA1004,400, HA1005,1000)

// 将数组转换为RDD:先并行化数组,然后按逗号分割,最后转换为Trans对象
scala> val acTransRDD = sc.parallelize(acTransList).map(_.split(",")).map(toTrans(_))

acTransRDD: org.apache.spark.rdd.RDD[Trans] = MapPartitionsRDD[31] at map at <console>:30

// 重复定义(实际使用中应删除重复定义)
scala> val acTransRDD = sc.parallelize(acTransList).map(_.split(",")).map(toTrans(_))

acTransRDD: org.apache.spark.rdd.RDD[Trans] = MapPartitionsRDD[34] at map at <console>:30

// 通过RDD创建DataFrame,Spark会自动根据case类的字段推断Schema
scala> val acTransDF = spark.createDataFrame(acTransRDD) //通过rdd创建df

acTransDF: org.apache.spark.sql.DataFrame = [accNo: string, tranAmount: double]

// 将DataFrame注册为临时视图,以便使用SQL查询
scala> acTransDF.createOrReplaceTempView("trans") //注册视图名称

// 打印DataFrame的Schema结构,显示字段名称和类型
scala> acTransDF.printSchema  //打印表结构

root

 |-- accNo: string (nullable = true)

 |-- tranAmount: double (nullable = true)

// 显示DataFrame中的数据内容,默认显示前20行
scala> acTransDF.show  //显示数据框的数据

+------+----------+
| accNo|tranAmount|
+------+----------+
|HA1001|  1000.0|
|HA1002|  2000.0|
|HA1003|  3000.0|
|HA1004|   400.0|
|HA1005|  1000.0|
+------+----------+

// 使用Spark SQL查询:筛选账户号以'HA'开头且交易金额大于1000的记录
scala> val goodTransRecords = spark.sql("select accNo,tranAmount from trans where accNo like 'HA%' AND tRANaMOUNT > 1000")

goodTransRecords: org.apache.spark.sql.DataFrame = [accNo: string, tranAmount: double]

// 将查询结果注册为另一个临时视图
scala> goodTransRecords.createOrReplaceTempView("goodTrans")

// 显示筛选后的交易记录
scala> goodTransRecords.show  //显示数据 

+------+----------+
| accNo|tranAmount|
+------+----------+
|HA1002|  2000.0|
|HA1003|  3000.0|
+------+----------+

3. 用户数据查询示例:使用RDD和DataFrame API

// 定义用户样例类,包含ID、姓名和编号三个字段
scala> case class User(id:Int,name:String,number:Int)

defined class User

// 定义转换函数:将字符串数组转换为User对象
// data(0).toInt 是用户ID,data(1) 是姓名,data(2).toInt 是编号
scala> def toUser(data:Seq[String]):User = User(data(0).toInt,data(1),data(2).toInt)

toUser: (data: Seq[String])User
 
// 通过Array创建RDD,数据格式为"ID,姓名,编号"
scala> val rdd = sc.makeRDD(Array("1,curry,30","2,tom,11","3,green,23"))

rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[57] at makeRDD at <console>:24

// 将RDD中的字符串按逗号分割,然后转换为User对象
scala> val rdd2 = rdd.map(_.split(",")).map(toUser(_))

rdd2: org.apache.spark.rdd.RDD[User] = MapPartitionsRDD[59] at map at <console>:30

// 将包含User对象的RDD转换为DataFrame
scala> val df = spark.createDataFrame(rdd2)

df: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

// 将DataFrame注册为临时视图,视图名为"users"
scala> df.createOrReplaceTempView("users")

// 显示DataFrame中的所有数据
scala> df.show

+---+-----+------+
| id| name|number|
+---+-----+------+
| 1|curry|  30|
| 2| tom|  11|
| 3|green|  23|
+---+-----+------+

// 使用SQL查询:查找姓名为'curry'的用户,collect()方法将结果收集到Driver端
scala> spark.sql("select * from users where name='curry'").collect

res20: Array[org.apache.spark.sql.Row] = Array([1,curry,30])

// SparkSession是使用DataFrame和DataSet API的入口点
// 使用builder模式创建或获取SparkSession实例
Val session = SparkSession.builder().getOrCreate();

4. Union操作:合并多个DataFrame

// 创建第一个DataFrame:查询编号大于11的用户
scala> val df1 = spark.sql("select * from users where number > 11")
 
df1: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

// 创建第二个DataFrame:查询编号小于11的用户
scala> val df2 = spark.sql("select * from users where number < 11")
 
df2: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

// 使用union方法合并两个DataFrame,union会去重,unionAll不会去重
scala> df1.union(df2).show
 
+---+-----+------+
| id| name|number|
+---+-----+------+
| 1|curry|  30|
| 3|green|  23|
+---+-----+------+
 

// 将两个DataFrame注册为临时视图
df1.createOrReplaceTempView("users1")
 
df2.createOrReplaceTempView("users2")
 
// 使用SQL的UNION操作合并两个查询结果
spark.sql("select * from users1 union select * from users2").show

5. 聚合函数:求和

// 使用SQL的SUM函数计算所有用户编号的总和
scala> spark.sql("select sum(number) from users").show

+-----------+
|sum(number)|
+-----------+
|     64|
+-----------+

6. 聚合函数:求最大值

// 使用SQL的MAX函数查找用户编号的最大值
scala> spark.sql("select max(number) from users").show

+-----------+
|max(number)|
+-----------+
|     30|
+-----------+

7. 聚合函数:求平均值

// 使用SQL的AVG函数计算用户编号的平均值
scala> spark.sql("select avg(number) from users").show

+------------------+
|    avg(number)|
+------------------+
|21.333333333333332|
+------------------+

8. 排序操作

// 使用SQL的ORDER BY子句按编号升序排序
scala> spark.sql("select id,name,number from users order by number").show

// 使用DataFrame API按订单号降序排序(示例代码)
Orders.orderBy(orders("orderno").desc).show

+---+-----+------+
| id| name|number|
+---+-----+------+
| 2| tom|  11|
| 3|green|  23|
| 1|curry|  30|
+---+-----+------+

// 使用RDD的map和reduce操作计算交易金额总和
scala> val sumAmountByMixing = goodTransRecords.map(trans =>trans.getAs[Double]("tranAmount")).reduce(_+_)

sumAmountByMixing: Double = 5000.0  

// 使用RDD的reduce操作计算交易金额的最大值
val maxAmountByMixing = goodTransRecords.map(trans =>trans.getAs[Double]("tranAmount")).reduce((a, b) => if (a > b) a else b)

maxAmountByMixing: Double = 10000.0

// 使用RDD的reduce操作计算交易金额的最小值
scala> val minAmountByMixing = goodTransRecords.map(trans =>trans.getAs[Double]("tranAmount")).reduce((a, b) => if (a < b) a else b)

minAmountByMixing: Double = 30.0

9. Between条件查询与DataFrame API操作

// 使用between方法筛选ID在2到4之间的订单(示例代码)
Orders.filter(orders("id").between(2,4)).show

// DataFrame API操作示例

// 显示DataFrame中的所有数据
scala> df.show

+---+-----+------+
| id| name|number|
+---+-----+------+
| 1|curry|  30|
| 3|green|  23|
+---+-----+------+

// 使用filter方法筛选编号等于30的记录
scala> df.filter("number=30").show

+---+-----+------+
| id| name|number|
+---+-----+------+
| 1|curry|  30|
+---+-----+------+

// 使用agg方法同时计算最大值、最小值和平均值
scala> df.agg(max("number"),min("number"),avg("number")).show

+-----------+-----------+-----------+                      
|max(number)|min(number)|avg(number)|
+-----------+-----------+-----------+
|     30|     23|    26.5|
+-----------+-----------+-----------+

// 筛选账户号以'SB'开头的记录,去重后按账户号排序
val goodAccNos = acTransDF.filter("accNo like'SB%'").select("accNo").distinct().orderBy("accNo")

// 按账户号降序排序显示
acTransDF.sort($"accNo".desc).show

10. Case when then

scala> customers.select(when(customers("name")==="curry",0).when(customers("name")==="tom",1).otherwise(2) as "type").show

+----+
|type|
+----+
|  0|
|  1|
|  2|
|  2|
|  2|
+----+

And 
customers.filter(customers("name").like("t%").and(customers("age").===(14))).show

11. 持久化数据到文件

// 将DataFrame以Parquet格式保存到指定路径(列式存储格式,高效压缩)
df.write.parquet("/opt/appl/df-write")
 
// 将DataFrame以JSON格式保存到指定路径
df.write.json("/opt/appl/df-write")
 
// RDD转换为DataFrame示例
// 创建包含元组的RDD
scala> val rdd = sc.makeRDD(Array((1,"curry",30),(2,"tom",11),(3,"green",23)))
 
rdd: org.apache.spark.rdd.RDD[(Int, String, Int)] = ParallelCollectionRDD[153] at makeRDD at <console>:24

12. 从文件读取持久化的数据

scala> val df2 = spark.read.parquet("/opt/appl/df-write")

df2: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

scala> df.show

+---+-----+------+
| id| name|number|
+---+-----+------+
| 1|curry|  30|
| 2| tom|  11|
| 3|green|  23|
+---+-----+------+

scala> val df = rdd.toDF

df: org.apache.spark.sql.DataFrame = [_1: int, _2: string ... 1 more field]

scala> df.show

+---+-----+---+
| _1|  _2| _3|
+---+-----+---+
| 1|curry| 30|
| 2| tom| 11|
| 3|green| 23|
+---+-----+---+

scala> val df = rdd.toDF("id","name","number")

df: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

scala> df.show

+---+-----+------+
| id| name|number|
+---+-----+------+
| 1|curry|  30|
| 2| tom|  11|
| 3|green|  23|
+---+-----+------+

13. 分组聚合操作

// 创建包含用户信息的RDD
scala> val rdd = sc.makeRDD(Array((1,"curry",30),(2,"tom",11),(3,"green",23),(4,"yigudala",23),(5,"drant",30)))

rdd: org.apache.spark.rdd.RDD[(Int, String, Int)] = ParallelCollectionRDD[165] at makeRDD at <console>:24

// 将RDD转换为DataFrame并指定列名
scala> val df = rdd.toDF("id","name","age")

df: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

// 按年龄分组,并计算每组中ID的最大值,结果列命名为"mag"
scala> df.groupBy("age").agg(max("id")as "mag").show

+---+---+                                   
|age|mag|
+---+---+
| 23| 4|
| 11| 2|
| 30| 5|
+---+---+

14. 连接查询:多种JOIN操作示例

// 创建客户数据RDD并转换为DataFrame
scala> val rdd1 = sc.makeRDD(Array((1,"curry",30),(2,"tom",11),(3,"green",23),(4,"yigudala",23),(5,"drant",30)))

rdd1: org.apache.spark.rdd.RDD[(Int, String, Int)] = ParallelCollectionRDD[177] at makeRDD at <console>:24

scala> val customers = rdd1.toDF("id","name","age")

customers: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]

// 创建订单数据RDD并转换为DataFrame
scala> val rdd2 = sc.makeRDD(Array((1,"no001",100.1,1),(2,"no002",100.2,2),(3,"no003",100.3,2),(4,"no004",100.4,3),(5,"no005",100.5,3)))

rdd2: org.apache.spark.rdd.RDD[(Int, String, Double, Int)] = ParallelCollectionRDD[178] at makeRDD at <console>:25

scala> val orders = rdd2.toDF("orderid","orderNo","price","cid")

orders: org.apache.spark.sql.DataFrame = [orderid: int, orderNo: string ... 2 more fields]

// 注册临时表(已废弃的方法,建议使用createOrReplaceTempView)
scala> customers.registerTempTable("customers")

warning: there was one deprecation warning; re-run with -deprecation for details

scala> orders.registerTempTable("orders")

warning: there was one deprecation warning; re-run with -deprecation for details

// 显示客户数据
scala> customers.show

+---+--------+---+
| id|  name|age|
+---+--------+---+
| 1|  curry| 30|
| 2|   tom| 11|
| 3|  green| 23|
| 4|yigudala| 23|
| 5|  drant| 30|
+---+--------+---+

// 显示订单数据
scala> orders.show

+-------+-------+-----+---+
|orderid|orderNo|price|cid|
+-------+-------+-----+---+
|   1| no001|100.1| 1|
|   2| no002|100.2| 2|
|   3| no003|100.3| 2|
|   4| no004|100.4| 3|
|   5| no005|100.5| 3|
+-------+-------+-----+---+

// 内连接(INNER JOIN):只返回两个表中匹配的记录
scala> spark.sql("select a.*,b.* from customers a,orders b where a.id = b.cid ").show

+---+-----+---+-------+-------+-----+---+                    
| id| name|age|orderid|orderNo|price|cid|
+---+-----+---+-------+-------+-----+---+
| 1|curry| 30|   1| no001|100.1| 1|
| 3|green| 23|   4| no004|100.4| 3|
| 3|green| 23|   5| no005|100.5| 3|
| 2| tom| 11|   3| no003|100.3| 2|
| 2| tom| 11|   2| no002|100.2| 2|
+---+-----+---+-------+-------+-----+---+

// 左外连接(LEFT OUTER JOIN):返回左表所有记录,右表无匹配则显示null
scala> spark.sql("select a.*,b.* from customers a left outer join orders b on a.id = b.cid ").show

+---+--------+---+-------+-------+-----+----+
| id|  name|age|orderid|orderNo|price| cid|
+---+--------+---+-------+-------+-----+----+
| 1|  curry| 30|   1| no001|100.1|  1|
| 3|  green| 23|   4| no004|100.4|  3|
| 3|  green| 23|   5| no005|100.5|  3|
| 5|  drant| 30|  null|  null| null|null|
| 4|yigudala| 23|  null|  null| null|null|
| 2|   tom| 11|   2| no002|100.2|  2|
| 2|   tom| 11|   3| no003|100.3|  2|
+---+--------+---+-------+-------+-----+----+

// 右外连接(RIGHT OUTER JOIN):返回右表所有记录,左表无匹配则显示null
scala> spark.sql("select a.*,b.* from customers a right outer join orders b on a.id = b.cid ").show

+---+-----+---+-------+-------+-----+---+
| id| name|age|orderid|orderNo|price|cid|
+---+-----+---+-------+-------+-----+---+
| 1|curry| 30|   1| no001|100.1| 1|
| 3|green| 23|   4| no004|100.4| 3|
| 3|green| 23|   5| no005|100.5| 3|
| 2| tom| 11|   2| no002|100.2| 2|
| 2| tom| 11|   3| no003|100.3| 2|
+---+-----+---+-------+-------+-----+---+

// 全外连接(FULL OUTER JOIN):返回两个表的所有记录,无匹配则显示null
scala> spark.sql("select a.*,b.* from customers a full outer join orders b on a.id = b.cid ").show

+---+--------+---+-------+-------+-----+----+
| id|  name|age|orderid|orderNo|price| cid|
+---+--------+---+-------+-------+-----+----+
| 1|  curry| 30|   1| no001|100.1|  1|
| 3|  green| 23|   4| no004|100.4|  3|
| 3|  green| 23|   5| no005|100.5|  3|
| 5|  drant| 30|  null|  null| null|null|
| 4|yigudala| 23|  null|  null| null|null|
| 2|   tom| 11|   3| no003|100.3|  2|
| 2|   tom| 11|   2| no002|100.2|  2|
+---+--------+---+-------+-------+-----+----+

// 词频统计示例:从文件读取数据,按空格分割,统计每个词的出现次数
val rdd = sc.textFile("/opt/appl/orders.txt")

val df = rdd.flatMap(_.split("\\s")).toDF("words")

df.createOrReplaceTempView("words")

// 统计词频,过滤空词,按出现次数降序排列
spark.sql("select word,count(word) as c from words group by word having length(word) >0 order by c desc").show(100)

// 使用DataFrame API实现内连接操作
// join后按姓名降序排序,并选择指定列
scala> customers.join(orders,customers("id") === orders("cid"),"inner").sort($"name".desc).select(customers("id"),customers("name"),orders("orderno"),orders("price")).show

+---+-----+-------+-----+                           
| id| name|orderno|price|
+---+-----+-------+-----+
| 2| tom| no003|100.3|
| 2| tom| no002|100.2|
| 3|green| no005|100.5|
| 3|green| no004|100.4|
| 1|curry| no001|100.1|
+---+-----+-------+-----+

15. Spark SQL多数据源操作

// 从外部文件加载数据
// 读取文本文件,按逗号分割,转换为DataFrame
val rdd = sc.textFile("/opt/appl/file.text")

rdd.map(_.split(",")).map(e=>(e(0),e(1),e(2),e(3))).toDF("id","name","age","addr").show

// 创建数据集(Dataset)
// 创建包含1到10的整数RDD
scala> val rdd = sc.makeRDD(1 to 10)

rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[259] at makeRDD at <console>:24

// 将RDD转换为Dataset,Dataset是类型安全的DataFrame
scala> val ds = rdd.toDS

ds: org.apache.spark.sql.Dataset[Int] = [value: int]

scala> ds

res58: org.apache.spark.sql.Dataset[Int] = [value: int]

// 将RDD转换为DataFrame
scala> val df = rdd.toDF

df: org.apache.spark.sql.DataFrame = [value: int]

scala> df

res59: org.apache.spark.sql.DataFrame = [value: int]

// Dataset支持链式过滤操作,筛选值大于5且小于7的记录
scala> ds.filter(_ > 5).filter(_ < 7).show

+-----+
|value|
+-----+
|  6|
+-----+

16. 数据集 dataSet 过滤操作

scala> val rdd = sc.makeRDD(Array((1,"curry"),(2,"kly"),(3,"green")))

rdd: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[270] at makeRDD at <console>:24

scala> val ds = rdd.toDS

ds: org.apache.spark.sql.Dataset[(Int, String)] = [_1: int, _2: string]

scala> ds.filter(a=>{(a _1)> 2}).show

warning: there was one feature warning; re-run with -feature for details

+---+-----+
| _1|  _2|
+---+-----+
| 3|green|
+---+-----+

17. Dataset Union操作

// Union操作要求:两个Dataset的列个数和类型必须相同

// 显示原始Dataset
scala> ds.show

+---+-----+
| _1|  _2|
+---+-----+
| 1|curry|
| 2| kly|
| 3|green|
+---+-----+

// 创建另一个相同结构的Dataset
scala> val ds2 = rdd.toDS

ds2: org.apache.spark.sql.Dataset[(Int, String)] = [_1: int, _2: string]

// 合并两个Dataset,union会保留重复记录
scala> ds.union(ds2).show

+---+-----+

| _1|  _2|

+---+-----+

| 1|curry|

| 2| kly|

| 3|green|

| 1|curry|

| 2| kly|

| 3|green|

+---+-----+

18. Dataset聚合:求和

// 使用map提取元组的第一个元素,然后使用reduce求和
scala> ds2.map(t=>t _1).reduce(_+_)

warning: there was one feature warning; re-run with -feature for details

res71: Int = 6

19. Dataset转换为DataFrame

// 将Dataset转换为DataFrame并指定列名
scala> val df = ds.toDF("id","name")

df: org.apache.spark.sql.DataFrame = [id: int, name: string]

scala> df.show

+---+-----+
| id| name|
+---+-----+
| 1|curry|
| 2| kly|
| 3|green|
+---+-----+

20. Catalog:查看表结构信息

// Catalog用于管理数据库的表结构信息,能够获取SparkSession的元数据信息
// 查看catalog可用的方法
scala> spark.catalog.

cacheTable      currentDatabase   dropTempView   getFunction  listColumns   listTables   setCurrentDatabase   

clearCache      databaseExists    functionExists  getTable   listDatabases  refreshByPath  tableExists       

createExternalTable  dropGlobalTempView  getDatabase   isCached   listFunctions  refreshTable  uncacheTable      

// 列出所有表,返回Dataset类型
scala> spark.catalog.listTables

res77: org.apache.spark.sql.Dataset[org.apache.spark.sql.catalog.Table] = [name: string, database: string ... 3 more fields]

// 显示所有表的信息:表名、数据库、描述、表类型、是否临时表
scala> spark.catalog.listTables.show // 查看所有表

+---------+--------+-----------+---------+-----------+
|   name|database|description|tableType|isTemporary|
+---------+--------+-----------+---------+-----------+
|customers|  null|    null|TEMPORARY|    true|
|goodtrans|  null|    null|TEMPORARY|    true|
|  orders|  null|    null|TEMPORARY|    true|
|  trans|  null|    null|TEMPORARY|    true|
|  users|  null|    null|TEMPORARY|    true|
+---------+--------+-----------+---------+-----------+

21. 删除临时视图

// 使用catalog删除临时视图,返回Boolean表示是否删除成功
scala> spark.catalog.dropTempView("users")

res80: Boolean = true

22. Java api


import org.apache.spark.{SparkConf, SparkContext}

import org.apache.spark.sql.SparkSession

object SparkSqlDemo1 {

 case class User(id:Int,name:String,age:Int)

 def toUser(data:Seq[String]) :User = User(data(0).toInt,data(1),data(2).toInt)

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

  val conf = new SparkConf()

  conf.setMaster("local[4]")

  conf.setAppName("sqlDemo")

  val sc = new SparkContext(conf)

  val session = SparkSession.builder().getOrCreate()

  import session.implicits._ //需要导入该包

  val rdd = sc.makeRDD(Array("1,curry,30","2,tom,11","3,green,23"))

  val rdd2 = rdd.map(_.split(",")).map(toUser(_))

val df = rdd2.toDF("id","name","age")

  df.foreach(e=>{

   println(e.getInt(0) + " : " + e.getString(1) + " : " + e.getInt(2))

  })

  val rdd2 = rdd.map(e=>{

   val ss = e.split(",")

   User(ss(0).toInt,ss(1),ss(2).toInt)

  })

  //创建数据框

  val df = session.createDataFrame(rdd2)

  df.show
 }
}

23. Spark SQL操作关系型数据库(MySQL)

// 步骤1:启动spark-shell时通过 --jars 指定MySQL驱动程序的jar路径
// ./spark-shell --master local --jars ../jars/mysql-connector-java-5.1.26-bin.jar

// 步骤2:通过spark.read.jdbc(url,table,prop)读取MySQL数据

// 创建Properties对象,用于存储数据库连接信息
scala> val prop = new java.util.Properties

prop: java.util.Properties = {}

// 设置数据库用户名
scala> prop.put("user","root")

res0: Object = null

// 设置数据库密码
scala> prop.put("password","root")

res1: Object = null

// 设置JDBC驱动类名(如果连接不上可以添加此配置)
scala> prop.put("driver","com.mysql.jdbc.Driver")

res3: Object = null

// 设置JDBC连接URL
scala> val url = "jdbc:mysql://slave1:3306/spark"

url: String = jdbc:mysql://slave1:3306/spark

// 设置要读取的表名
scala> val table = "users"

table: String = users

// 通过JDBC读取MySQL表数据
scala> val df = spark.read.jdbc(url,table,prop)

df: org.apache.spark.sql.DataFrame = [userid: bigint, username: string ... 1 more field]

// 显示读取的数据
scala> df.show

+------+--------+---+
|userid|username|age|
+------+--------+---+
|   1|  curry| 29|
|   2|  kely| 28|
|   3|  green| 23|
+------+--------+---+

// 使用filter过滤数据
scala> df.filter("userid=3").show

+------+--------+---+
|userid|username|age|
+------+--------+---+
|   3|  green| 23|
+------+--------+---+

24. 保存数据到MySQL

// 将DataFrame写入MySQL数据库,表名为"spark02"
scala> df.write.jdbc(url,"spark02",prop)

// 显示原始DataFrame数据
scala> df.show

+------+--------+---+
|userid|username|age|
+------+--------+---+
|   1|  curry| 29|
|   2|  kely| 28|
|   3|  green| 23|
+------+--------+---+

25. 加载外部脚本执行

25.1 先创建脚本文件 spark_mysql.scala

val rdd = sc.makeRDD(Array((1,"curry"),(2,"kly"),(3,"green"))

val prop = new java.util.Properties

prop.put("user","root")

prop.put("password","root")

prop.put("driver","com.mysql.jdbc.Driver")

val url = "jdbc:mysql://slave1:3306/spark"

val table = "users"

val df = spark.read.jdbc(url,table,prop)

25.2 Scala 加载外部文件

scala> :load /opt/appl/spark_mysql.scala

Loading /opt/appl/spark_mysql.scala...

prop: java.util.Properties = {}

res10: Object = null

res11: Object = null

res12: Object = null

url: String = jdbc:mysql://slave1:3306/spark

table: String = users

dff: org.apache.spark.sql.DataFrame = [userid: bigint, username: string ... 1 more field]

scala> dff.show

+------+--------+---+
|userid|username|age|
+------+--------+---+
|   1|  curry| 29|
|   2|  kely| 28|
|   3|  green| 23|
+------+--------+---+

26. Spark-Java api 调用msyql

import org.apache.spark.sql.SparkSession

/**
 * Created by hnbia on 2017/4/3.
 * spark sql 操作mysql
 **/

object SparkSql_Mysql {

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

  val session = SparkSession.*builder*().master("local[4]").appName("spark-mysql-demo").getOrCreate()

  val prop = new java.util.Properties

  prop.put("user","root")

  prop.put("password","root")

  prop.put("driver","com.mysql.jdbc.Driver")

  val url = "jdbc:mysql://slave1:3306/spark"

  val table = "users"

  //注册驱动
  Class.forName("com.mysql.jdbc.Driver")

  val df = session.read.jdbc(url,table,prop)

  df.show

  df.foreach(e=>{
   println(e.getLong(0) + " : " + e.getString(1)+" : "+ e.getString(2))
  })

   //写入数据
  df.filter("userid=3").write.jdbc(url,"spark03",prop)
 }
}

27. Spark SQL操作Hive

27.1. 配置说明

如果没有hive依赖,spark会自动加载hive的依赖库,注意所有的依赖需要出现在worker节点中
配置hive只需要复制core-site.xml、hdfs-site.xml、hive-site.xml 三个文档到spark/conf目录下即可
如果没有配置hive-site.xml,spark启动时会在当前目录下创建metastore_db 和spark-warehouse两个目录

27.2. 使用Hive时,必须使用enableHiveSupport选项创建session实例

import org.apache.spark.sql.Row

import org.apache.spark.sql.SparkSession

// 创建支持Hive的SparkSession
val sparks = SparkSession.builder().appName("spark-hive").enableHiveSupport().getOrCreate()

scala> import org.apache.spark.sql.Row

import org.apache.spark.sql.Row

scala> import org.apache.spark.sql.SparkSession

import org.apache.spark.sql.SparkSession

scala> val sparks = SparkSession.builder().appName("spark-hive").enableHiveSupport().getOrCreate()

17/04/03 22:20:03 WARN sql.SparkSession$Builder: Using an existing SparkSession; some configuration may not take effect.

sparks: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@5f8eae05

// 使用SQL查询显示所有数据库
scala> sparks.sql("show databases").show

+------------+
|databaseName|
+------------+
|   default|
+------------+

28. Spark SQL分布式查询引擎(Thrift Server)

// Thrift Server允许通过JDBC/ODBC连接访问Spark SQL

// 步骤1:启动spark中的thrift-server
// sbin/start-thriftserver.sh --master local[4]

// 步骤2:查看启动是否成功,默认端口为10000
// netstat -ano|grep 10000

[root@master1 sbin]# netstat -ano | grep 10000

tcp    0   0 :::10000          :::*            LISTEN   off (0.00/0/0)

29. Beeline连接Thrift服务

// 启动Beeline客户端
[root@master1 bin]# beeline 

Beeline version 1.2.1.spark2 by Apache Hive

// 连接到Thrift Server
beeline> !connect jdbc:hive2://master1:10000

Connecting to jdbc:hive2://master1:10000

Enter username for jdbc:hive2://master1:10000: 回车

Enter password for jdbc:hive2://master1:10000: 回车

17/04/03 22:54:46 INFO jdbc.Utils: Supplied authorities: master1:10000

17/04/03 22:54:46 INFO jdbc.Utils: Resolved authority: master1:10000

17/04/03 22:54:46 INFO jdbc.HiveConnection: Will try to open client transport with JDBC Uri: jdbc:hive2://master1:10000

Connected to: Spark SQL (version 2.1.0)

Driver: Hive JDBC (version 1.2.1.spark2)

Transaction isolation: TRANSACTION_REPEATABLE_READ

// 连接成功后可以执行SQL查询
0: jdbc:hive2://master1:10000> show tables; //连接成功

+-----------+------------+--------------+--+
| database | tableName | isTemporary |
+-----------+------------+--------------+--+

+-----------+------------+--------------+--+

No rows selected (0.825 seconds)

// 显示所有数据库
0: jdbc:hive2://master1:10000> show databases;

+---------------+--+
| databaseName |
+---------------+--+
| default    |
+---------------+--+

1 row selected (0.639 seconds)

0: jdbc:hive2://master1:10000> 

30. 通过jdbc API远程连接到sparksql 分布式查询引擎

import java.sql.DriverManager

/**
 * Created by hnbia on 2017/4/4.
 **/

object SaprkSql_Hive {

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

  //注册驱动

  Class.forName("org.apache.hive.jdbc.HiveDriver")

  val conn = DriverManager.getConnection("jdbc:hive2://master1:10000")

  val st = conn.createStatement()

  val rs = st.executeQuery("show databases")

  while(rs.next()){

   println(rs.getString(1))

  }

  println("over! . . .")
 }

31. Spark SQL操作PostgreSQL数据库示例

// 方式1:使用format和option方式读取PostgreSQL数据
// 通过指定format为"jdbc",然后配置连接URL、表名、用户名和密码
val jdbcDF = spark.read
  .format("jdbc")
  .option("url", "jdbc:postgresql:dbserver")
  .option("dbtable", "schema.tablename")
  .option("user", "username")
  .option("password", "password")
  .load()

// 方式2:使用Properties对象和jdbc方法读取PostgreSQL数据
// 创建Properties对象存储连接属性
val connectionProperties = new Properties()
connectionProperties.put("user", "username")
connectionProperties.put("password", "password")
// 直接使用jdbc方法,传入URL、表名和Properties对象
val jdbcDF2 = spark.read
  .jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)

// 方式1:使用format和option方式保存数据到PostgreSQL
// 通过指定format为"jdbc",然后配置连接URL、表名、用户名和密码
jdbcDF.write
  .format("jdbc")
  .option("url", "jdbc:postgresql:dbserver")
  .option("dbtable", "schema.tablename")
  .option("user", "username")
  .option("password", "password")
  .save()

// 方式2:使用jdbc方法保存数据到PostgreSQL
// 直接使用jdbc方法,传入URL、表名和Properties对象
jdbcDF2.write
  .jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)

文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录