2.1 SparkSession新的起始点
在老的版本中,SparkSQL提供两种SQL查询起始点:
- 一个叫SQLContext,用于Spark自己提供的SQL查询;
- 一个叫HiveContext,用于连接Hive的查询。
SparkSession是Spark最新的SQL查询起始点,实质上是SQLContext和HiveContext的组合,所以在SQLContext和HiveContext上可用的API在SparkSession上同样是可以使用的。
SparkSession内部封装了SparkContext,所以计算实际上是由SparkContext完成的。当我们使用spark-shell的时候,Spark框架会自动的创建一个名称叫做Spark的SparkSession,就像我们以前可以自动获取到一个sc来表示SparkContext。
[atguigu@hadoop102 spark-local]$ bin/spark-shell
20/09/12 11:16:35 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
Spark context Web UI available at http://hadoop102:4040
Spark context available as 'sc' (master = local[*], app id = local-1599880621394).
Spark session available as 'spark'.
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ `/ __/ '_/
/___/ .__/\_,_/_/ /_/\_\ version 3.3.1
/_/
Using Scala version 2.12.10 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_212)
Type in expressions to have them evaluated.
Type :help for more information.
2.2 常用方式
2.2.1 方法调用
1)创建一个maven工程SparkSQL
2)创建包名为com.atguigu.sparksql
3)输入文件夹准备:在新建的SparkSQL项目名称上右键=》新建input文件夹=》在input文件夹上右键=》新建user.json。并输入如下内容:
{"age":20,"name":"qiaofeng"}
{"age":19,"name":"xuzhu"}
{"age":18,"name":"duanyu"}
{"age":22,"name":"qiaofeng"}
{"age":11,"name":"xuzhu"}
{"age":12,"name":"duanyu"}
5)在pom.xml文件中添加spark-sql的依赖
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.12</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
6)代码实现
添加javaBean的User
package com.atguigu.sparksql.Bean;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
public Long age;
public String name;
public User() {
}
public User(Long age, String name) {
this.age = age;
this.name = name;
}
}
代码编写
package com.atguigu.sparksql;
import com.atguigu.sparksql.Bean.User;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.function.MapFunction;
import org.apache.spark.api.java.function.ReduceFunction;
import org.apache.spark.sql.*;
import scala.Tuple2;
public class Test01_Method {
public static void main(String[] args) {
//1. 创建配置对象
SparkConf conf = new SparkConf().setAppName("sparksql").setMaster("local[*]");
//2. 获取sparkSession
SparkSession spark = SparkSession.builder().config(conf).getOrCreate();
//3. 编写代码
// 按照行读取
Dataset<Row> lineDS = spark.read().json("input/user.json");
// 转换为类和对象
Dataset<User> userDS = lineDS.as(Encoders.bean(User.class));
// userDS.show();
// 使用方法操作
// 函数式的方法
Dataset<User> userDataset = lineDS.map(new MapFunction<Row, User>() {
@Override
public User call(Row value) throws Exception {
return new User(value.getLong(0), value.getString(1));
}
},
// 使用kryo在底层会有部分算子无法使用
Encoders.bean(User.class));
// 常规方法
Dataset<User> sortDS = userDataset.sort(new Column("age"));
sortDS.show();
// 区分
RelationalGroupedDataset groupByDS = userDataset.groupBy("name");
// 后续方法不同
Dataset<Row> count = groupByDS.count();
// 推荐使用函数式的方法 使用更灵活
KeyValueGroupedDataset<String, User> groupedDataset = userDataset.groupByKey(new MapFunction<User, String>() {
@Override
public String call(User value) throws Exception {
return value.name;
}
}, Encoders.STRING());
// 聚合算子都是从groupByKey开始
// 推荐使用reduceGroup
Dataset<Tuple2<String, User>> result = groupedDataset.reduceGroups(new ReduceFunction<User>() {
@Override
public User call(User v1, User v2) throws Exception {
// 取用户的大年龄
return new User(Math.max(v1.age, v2.age), v1.name);
}
});
result.show();
//4. 关闭sparkSession
spark.close();
}
}
在sparkSql中DS直接支持的转换算子有:map(底层已经优化为mapPartition)、mapPartition、flatMap、groupByKey(聚合算子全部由groupByKey开始)、filter、distinct、coalesce、repartition、sort和orderBy(不是函数式的算子,不过不影响使用)。
2.2.2 SQL使用方式
package com.atguigu.sparksql;
import org.apache.spark.SparkConf;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class Test02_SQL {
public static void main(String[] args) {
//1. 创建配置对象
SparkConf conf = new SparkConf().setAppName("sparksql").setMaster("local[*]");
//2. 获取sparkSession
SparkSession spark = SparkSession.builder().config(conf).getOrCreate();
//3. 编写代码
Dataset<Row> lineDS = spark.read().json("input/user.json");
// 创建视图 => 转换为表格 填写表名
// 临时视图的生命周期和当前的sparkSession绑定
// orReplace表示覆盖之前相同名称的视图
lineDS.createOrReplaceTempView("t1");
// 支持所有的hive sql语法,并且会使用spark的又花钱
Dataset<Row> result = spark.sql("select * from t1 where age > 18");
result.show();
//4. 关闭sparkSession
spark.close();
}
}}
2.2.3 DSL特殊语法(扩展)
package com.atguigu.sparksql;
import org.apache.spark.SparkConf;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import static org.apache.spark.sql.functions.col;
public class Test03_DSL {
public static void main(String[] args) {
//1. 创建配置对象
SparkConf conf = new SparkConf().setAppName("sparksql").setMaster("local[*]");
//2. 获取sparkSession
SparkSession spark = SparkSession.builder().config(conf).getOrCreate();
//3. 编写代码
// 导入特殊的依赖 import static org.apache.spark.sql.functions.col;
Dataset<Row> lineRDD = spark.read().json("input/user.json");
Dataset<Row> result = lineRDD.select(col("name").as("newName"),col("age").plus(1).as("newAge"))
.filter(col("age").gt(18));
result.show();
//4. 关闭sparkSession
spark.close();
}
}