一、 核心认知(一句话总结)
Spark SQL 是 Spark 用于处理结构化数据的模块,支持 SQL 查询和 DataFrame/Dataset API,Java 操作 Spark SQL 本质是通过 Spark 提供的 Java 客户端 API,加载结构化数据、构建 DataFrame/Dataset、执行 SQL 或 DSL 操作,最终输出结果,适合大数据量的结构化数据处理(如日志分析、数仓ETL)。
二、 前置准备(必做步骤)
- 引入依赖(Maven 核心依赖,Spark 3.x 为例)
<dependencies>
<!-- Spark SQL 核心依赖 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.12</artifactId>
<version>3.4.0</version>
<!-- 本地开发无需打包,集群运行需改为 provided -->
<scope>compile</scope>
</dependency>
</dependencies>
- 环境要求
- JDK 8+(Spark 3.x 推荐 JDK 8/11)
- 本地开发可无需部署 Spark 集群,使用本地模式(
local[*]) - 集群运行需将打包后的 Jar 包提交到 Spark 集群
三、 Java 操作 Spark SQL 核心流程(完整可运行示例)
核心步骤:创建 SparkSession → 加载数据构建 DataFrame → 注册临时视图 → 执行 SQL 查询 → 处理结果 → 关闭 SparkSession
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class JavaSparkSQLDemo {
public static void main(String[] args) {
// 1. 创建 SparkSession(Spark SQL 的入口,相当于 JDBC 的 Connection)
SparkSession spark = SparkSession.builder()
.appName("JavaSparkSQLDemo") // 应用名称
.master("local[*]") // 本地模式,[*] 表示使用所有可用CPU核心,集群运行时删除该行
.getOrCreate();
try {
// 2. 加载数据构建 DataFrame(两种常见方式:加载本地文件 / 构建内存数据)
// 方式2.1:加载 CSV 文件(带表头)
Dataset<Row> csvDF = spark.read()
.option("header", "true") // 第一行作为表头
.option("inferSchema", "true") // 自动推断字段类型
.csv("src/main/resources/user.csv"); // 本地 CSV 文件路径
// 方式2.2:构建内存数据(演示用,无需外部文件)
Dataset<Row> inMemoryDF = spark.createDataFrame(
// 封装数据(这里简化,实际可通过 JavaBean 构建)
java.util.Arrays.asList(
new User("张三", 25),
new User("李四", 30),
new User("王五", 28)
), User.class
);
// 3. 注册临时视图(将 DataFrame 注册为 SQL 可查询的视图,类似数据库表)
// 临时视图:仅当前 SparkSession 有效,关闭后失效
inMemoryDF.createOrReplaceTempView("t_user");
// 4. 执行 Spark SQL 查询(两种方式:纯 SQL / DSL 语法)
// 方式4.1:执行纯 SQL 语句
Dataset<Row> sqlResult = spark.sql("SELECT name, age FROM t_user WHERE age > 26");
// 方式4.2:使用 DSL 语法(无需写 SQL,链式调用)
Dataset<Row> dslResult = inMemoryDF.select("name", "age").where("age > 26");
// 5. 处理并输出结果(show() 打印到控制台,实际可写入 HDFS/MySQL 等)
System.out.println("=== SQL 查询结果 ===");
sqlResult.show(); // 打印前20行数据
System.out.println("=== DSL 查询结果 ===");
dslResult.show();
// 6. (可选)将结果写入外部存储(如 Parquet 文件)
sqlResult.write()
.mode("overwrite") // 覆盖已有文件
.parquet("src/main/resources/result_parquet");
} finally {
// 7. 关闭 SparkSession,释放资源
spark.close();
}
}
// 定义 JavaBean 类,用于构建内存 DataFrame(字段需提供 getter/setter,序列化)
public static class User {
private String name;
private int age;
// 必须提供无参构造器(Spark 反射推断 schema 所需)
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
// getter 和 setter(必须提供,否则 Spark 无法读取字段)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
}
补充说明
- 本地测试时,创建
user.csv文件放在src/main/resources/下,内容示例:name,age,gender 张三,25,男 李四,30,男 王五,28,女 - 运行结果:控制台会打印年龄大于 26 的用户(李四、王五),同时生成
result_parquet结果文件。
四、 关键注意点(有主见的核心提醒)
- SparkSession 是入口:所有 Spark SQL 操作都围绕
SparkSession展开,相当于 JDBC 中的Connection,无需再创建SparkContext(Spark 3.x 中SparkSession已封装)。 - 临时视图 vs 全局临时视图:
createOrReplaceTempView:仅当前SparkSession有效,适合单任务查询。createGlobalTempView:跨SparkSession有效,视图名需带global_temp.前缀(如SELECT * FROM global_temp.t_user),适合多任务共享数据。
- JavaBean 规范:用于构建 DataFrame 的 JavaBean 必须满足:提供无参构造器、所有字段有 getter/setter、实现序列化(可选,推荐),否则 Spark 无法反射推断字段类型。
- 本地模式 vs 集群模式:本地开发时用
master("local[*]"),提交到 Spark 集群时需删除该行,由集群的spark-submit命令指定--master参数。 - 数据写入模式:
write().mode()支持overwrite(覆盖)、append(追加)、ignore(忽略已存在)、errorIfExists(默认,存在则报错)。
五、 实际业务场景延伸
- 连接外部数据库(如 MySQL):引入
spark-sql-connector-mysql依赖,通过spark.read().jdbc()加载数据,适合数仓同步。 - 自定义 UDF 函数:通过
spark.udf().register()注册自定义函数,扩展 SQL 功能(如复杂数据处理)。 - 性能优化:避免全表扫描,使用
filter()提前过滤数据,合理设置分区(repartition()),优先使用 Parquet 等列式存储格式。
总结
- Java 操作 Spark SQL 的核心是通过
SparkSession完成「数据加载→视图注册→SQL/DSL 查询→结果输出」的流程。 - 前置依赖需引入
spark-sql_2.12,本地开发用local[*]模式,JavaBean 需满足无参构造器和 getter/setter 规范。 - 适合大数据结构化数据处理,集群运行时需删除本地模式配置,通过
spark-submit提交 Jar 包。
浙公网安备 33010602011771号