Spark SQL

Spark SQL 是Spark用于结构化数据处理的模块,提供SparkSession接口与多种数据源交互,支持SQL查询和DataFrame/Dataset API。内容涵盖SparkSession、算子、DataFrame/Dataset操作、SQL查询、数据加载与保存,以及Spark Catalyst优化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spark SQL

Spark SQL是用于结构化数据处理的一个模块。同Spark RDD 不同地方在于Spark SQL的API可以给Spark计算引擎提供更多地信息,例如:数据结构、计算算子等。在内部Spark可以通过这些信息有针对对任务做优化和调整。这里有几种方式和Spark SQL进行交互,例如Dataset API和SQL等,这两种API可以混合使用。Spark SQL的一个用途是执行SQL查询。 Spark SQL还可用于从现有Hive安装中读取数据。从其他编程语言中运行SQL时,结果将作为Dataset/DataFrame返回,使用命令行或JDBC / ODBC与SQL接口进行交互。

Dataset是一个分布式数据集合在Spark 1.6提供一个新的接口,Dataset提供RDD的优势(强类型,使用强大的lambda函数)以及具备了Spark SQL执行引擎的优点。Dataset可以通过JVM对象构建,然后可以使用转换函数等(例如:map、flatMap、filter等),目前Dataset API支持Scala和Java 目前Python对Dataset支持还不算完备。

Data Frame是命名列的数据集,他在概念是等价于关系型数据库。DataFrames可以从很多地方构建,比如说结构化数据文件、hive中的表或者外部数据库,使用Dataset[row]的数据集,可以理解DataFrame就是一个Dataset[row].

原文链接:https://blog.youkuaiyun.com/weixin_38231448/article/details/89920804

一、SparkSession

Spark中所有功能的入口点是SparkSession类。

   <dependencies>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>2.4.5</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <!--scala编译插件-->
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>4.0.1</version>
                <executions>
                    <execution>
                        <id>scala-compile-first</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!--创建fatjar插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!--编译插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

①.算子:
//普通的 
package com.baizhi.qickdemo

import com.baizhi.User
import org.apache.spark.sql.SparkSession

case class User(id:Int,name:String,deptno:Int,salary:Double) {
   }
object SparkSQLHelloWold01 {
   

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

    //1.构建SparkSession
    val spark = SparkSession.builder()
      .appName("hello world")
      .master("local[*]")
      .getOrCreate()
    //可以将一个集合、RDD转换为Dataset或者是Dataframe
    import spark.implicits._
    spark.sparkContext.setLogLevel("FATAL") //设置日志级别

    //2.创建Dataset或者是Dataframe
    var users:List[User]=List(new User(2,"lisi",2,1000),
      new User(1,"zhangsan",1,1000),new User(3,"wangwu",1,1500))
    val userDateframe = users.toDF()

    //3.SparkSQL提供的算子或者SQL脚本
    val resultDataFrame = userDateframe.select("id", "name", "salary", "deptNo")

    //4.将SQL结果写出带外围系统
    resultDataFrame.show()//打印最终结果

    //5.关闭session
    spark.close()
  }
}

日志文件:

#自定义日志
log4j.rootLogger = FATAL,stdout

log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %p %d{yyyy-MM-dd HH:mm:ss} %c %m%n
②.SQL脚本:
package com.baizhi

import com.baizhi.User
import org.apache.spark.sql.SparkSession

case class User(id:Int,name:String,deptno:Int,salary:Double) {
   }
object SparkSQLHelloWold01 {
   

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

    //1.构建SparkSession
    val spark = SparkSession.builder()
      .appName("hello world")
      .master("local[*]")
      .getOrCreate()
    //可以将一个集合、RDD转换为Dataset或者是Dataframe
    import spark.implicits._
    spark.sparkContext.setLogLevel("FATAL")

    //2.创建Dataset或者是Dataframe
    var users:List[User]=List(new User(2,"lisi",2,1000),
      new User(1,"zhangsan",1,1000),new User(3,"wangwu",1,1500))
    val userDateframe = users.toDF()

    //注册表
    userDateframe.createOrReplaceTempView("t_user")

    //3.SparkSQL提供的算子或者SQL脚本
    val resultDataFrame = spark.sql("select id,name,deptNo,salary,salary * 12 as annual_salary from t_user")

    //4.将SQL结果写出带外围系统
    resultDataFrame.show()//打印最终结果

    //5.关闭session
    spark.close()
  }
}

DataSet

Dataset与RDD类似,但是,它们不使用Java序列化或Kryo,而是使用专用的Encoder来序列化对象以便通过网络进行处理或传输。虽然Encoder和标准序列化都负责将对象转换为字节,但Encoder是动态生成的代码,并使用一种格式,允许Spark执行许多操作,如过滤,排序和散列,而无需将字节反序列化为对象。

①.json数据

json文件:

{
   "name":"zly","age":20}
{
   "name":"zly","age":21}
{
   "name":"zly3","age":22}
package com.baizhi

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

case class Person2(name:String,age:Long){
   }
object DataSet3 {
   
  def main(args: Array[String]): Unit = {
   
    //1.创建一个SparkSession对象
    val sparkSession = SparkSession.builder().master("local[*]").appName("dataset1").getOrCreate()
    //.2.设置日志等级
    //引入隐式转换
    //可以将一个集合、RDD转换为Dataset或者是Dataframe
    import sparkSession.implicits._
    sparkSession.sparkContext.setLogLevel("FATAL")

    //创建dataset
    val dataset = sparkSession.read.json("E:\\文档\\大数据\\feiq\\Recv Files\\08-Spark\\代码\\SparkSql\\src\\main\\resources\\word.json").as[Person2]

    dataset.show()

    //5.关闭sparkSession
    sparkSession.stop()
  }

}
②.RDD数据
 //创建dataset
    val Rdd = sparkSession.sparkContext.makeRDD(List((2,"zyl",20)))
    val dataset = Rdd.toDS()

DataFrame

Data Frame是命名列的数据集,他在概念是等价于关系型数据库。DataFrames可以从很多地方构建,比如说结构化数据文件、hive中的表或者外部数据库,使用Dataset[row]的数据集,可以理解DataFrame就是一个Dataset[row]。

①.json文件
  //创建dataframe
    val dataframe = sparkSession.read.json("E:\\文档\\大数据\\feiq\\Recv Files\\08-Spark\\代码\\SparkSql\\src\\main\\resources\\word.json")

    dataframe.show()
②.元祖
//创建dataframe
    val frame = sparkSession.sparkContext.parallelize(List("zyl1 23", "zyl2 24"))
      .map(x => (x.split(" ")(0) ,x.split(" ")(1).toInt))
      .toDF("theName","theAge")//可以自定义列名
    frame.show()
③.自定义schema
package dataframe

import org.apache.spark.rdd.RDD
import org.apache.spark.sql.types.{
   BooleanType, DoubleType, IntegerType, StringType, StructField, StructType}
import org.apache.spark.sql.{
   Row, SparkSession}

object TestCreateDataFrame04 {
   
  def main(args: Array[String]): Unit = {
   
    //1.构建SparkSession
    val spark = SparkSession.builder()
      .appName("hello world")
      .master("local[*]")
      .getOrCreate()

    import spark.implicits._
    //可以将一个集合、RDD转换为Dataset或者是Dataframe
    spark.sparkContext.setLogLevel("FATAL")

    val userRDD:RDD[Row] = spark.sparkContext.makeRDD(List((1,"张三",true,18,15000.0)))
      .map(t=>Row(t._1,t._2,t._3,t._4,t._5))

    val fields = Array(new StructField("id", IntegerType),
      new StructField("name", StringType),
      new StructField("sex", BooleanType),
      new StructField("age", IntegerType),
      new StructField("salary", DoubleType))
    val schema = new StructType(fields)

    val userDataframe = spark.createDataFrame(userRDD, schema)
    userDataframe.show()

    //5.关闭session
    spark.close()
  }

}
④.java类型

定义一个java类型

package dataframe;

import java.io.Serializable;

public class JavaUser implements Serializable {
   
    private Integer id;
    private String name;


    public JavaUser(Integer id,String name){
   
        this.id=id;
        this.name=name;
    }
    public JavaUser(){
   

    }

    public Integer getId() {
   
        return id;
    }

    public String getName() {
   
        return name;
    }

    public void setId(Integer id) {
   
        this.id=id;
    }

    public void setName(String name) {
   
        this.name = name;
    }

}

使用:

//创建一个集合
    val userList = List(new 
<think>嗯,用户想了解关于Spark SQL的使用指南和最佳实践。首先,我需要确定用户的具体需求是什么。他们可能刚接触Spark SQL,需要从基础开始,比如安装配置,或者已经有一定基础,想了解更高级的功能和优化技巧。根据提供的引用内容,我需要结合安装配置、核心功能、性能优化等方面来组织回答。 首先,安装配置部分。用户可能需要知道如何在不同环境下安装Spark SQL,比如独立模式或者集成到Hadoop/YARN。引用里提到Spark SQL支持多种数据源,比如Hive表、JSON、CSV等,所以在安装时需要确保这些依赖项正确配置。需要检查Spark的配置文件,比如spark-defaults.conf,设置内存参数,还有如何启用Hive支持。 然后是核心功能和使用方法。用户可能想了解如何创建DataFrame,执行SQL查询,以及如何连接不同的数据源。引用中提到可以使用SparkSQL从现有的Hive安装读取数据,执行SQL查询返回Dataset/DataFrame。这部分需要详细说明,比如使用spark.read.json()加载数据,或者用spark.sql("SELECT ...")执行查询。还要提到Catalyst优化器和Tungsten引擎,因为它们对性能很重要。 接下来是性能优化。引用里提到了广播变量和RDD缓存,这两个都是关键点。广播变量适合用于小表的join,避免shuffle,而缓存可以复用中间数据,减少重复计算。此外,分区和并行度设置也很重要,需要根据数据量和集群资源调整。可能还需要提到序列化格式,比如Parquet或ORC,以及内存管理,避免OOM错误。 最佳实践部分,应该包括数据格式的选择,比如列式存储,以及如何管理执行计划,比如使用explain查看优化后的逻辑。另外,错误处理和数据校验也是用户关心的问题,比如处理缺失数据或schema不一致的情况。 用户可能还会遇到一些常见问题,比如如何调优Spark SQL作业,或者如何处理大数据时的性能瓶颈。需要结合引用中的优化方法,比如缓存、广播变量,以及调整配置参数。同时,引用中提到的流式处理,结合Structured Streaming,可能也是用户感兴趣的部分,可以简要提及实时数据处理的应用。 最后,生成的相关问题需要覆盖用户可能进一步探索的方向,比如Catalyst优化器原理、数据倾斜处理、与其他模块整合等。确保问题能够引导用户深入学习和解决问题。 总结下来,回答的结构应该是:安装配置 -> 核心功能 -> 性能优化 -> 最佳实践 -> 相关问题。每个部分都要结合引用中的内容,确保信息准确,并且提供具体的代码示例帮助用户理解。同时,语言要简洁明了,符合中文表达习惯,避免技术术语过于晦涩。</think># Spark SQL 使用指南与最佳实践 ## 一、安装与基础配置 1. **环境依赖** Spark SQL 需要 Java 8+、Scala 2.12+ 和 Hadoop 2.7+ 环境。安装时需确保: ```bash # 下载预编译版本(含Hive支持) wget https://archive.apache.org/dist/spark/spark-3.3.1/spark-3.3.1-bin-hadoop3.tgz tar -xvf spark-3.3.1-bin-hadoop3.tgz ``` 2. **Hive 集成配置** 在 `conf/spark-defaults.conf` 中添加: ``` spark.sql.catalogImplementation=hive spark.sql.warehouse.dir=/user/hive/warehouse ``` 通过 `spark-shell --master yarn` 启动时自动加载 Hive 元数据[^3]。 ## 二、核心功能与基础操作 ### 1. DataFrame 操作 ```python # 从JSON创建DataFrame df = spark.read.json("hdfs://path/to/data.json") df.select("name", "age").filter(df.age > 30).show() # SQL查询 df.createOrReplaceTempView("people") spark.sql("SELECT AVG(age) FROM people WHERE gender='M'").show() ``` 支持结构化文件(JSON/CSV)、Hive 表、JDBC 数据库等数据源[^3]。 ### 2. 流式数据处理 ```scala val streamingDF = spark.readStream .schema(schema) .json("s3://logs/") val query = streamingDF.writeStream .outputMode("append") .format("console") .start() ``` 结合 Structured Streaming 实现实时 ETL[^1]。 ## 三、性能优化实践 ### 1. 内存管理优化 | 参数 | 建议值 | 说明 | |------|--------|------| | `spark.executor.memory` | 集群总内存的 60% | 保留部分内存给OS | | `spark.sql.shuffle.partitions` | 200-1000 | 根据数据量调整 | ### 2. 高级优化技术 - **广播 Join**(适合小表关联): ```sql SELECT /*+ BROADCAST(small_table) */ * FROM large_table JOIN small_table ON key ``` - **缓存复用**: ```python df.cache() # MEMORY_AND_DISK df.unpersist() ``` 通过缓存中间结果减少重复计算[^4]。 ### 3. 数据存储优化 ```python df.write.parquet("hdfs://output.parquet") # 列式存储 spark.read.parquet("hdfs://input.parquet") ``` 建议优先使用 Parquet/ORC 格式,压缩率可达 70%+。 ## 四、最佳实践指南 1. **执行计划分析** ```python df.explain(mode="formatted") # 查看优化后逻辑计划 ``` 2. **错误处理** - 使用 `na.fill()` 处理空值 - 通过 `withColumn` 添加数据校验逻辑 3. **资源监控** ```bash spark-submit --conf spark.metrics.conf=/path/to/metrics.properties ``` 配合 Grafana 监控 GC 时间/Shuffle 量等指标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值