sparkSQL背景
- sparkContext:
SparkContext
是 Spark 应用程序的入口点,它代表了与 Spark 集群的连接。- 它是 Spark 1.x 版本中的主要入口点,在 Spark 2.x 版本中引入了
SparkSession
来替代SparkContext
。 SparkContext
负责管理任务调度、数据分区和与集群的通信。- 你可以使用
SparkContext
来创建 RDD(弹性分布式数据集)并执行基本的 Spark 操作,例如 map、reduce 等。 - 通常,你会在 Spark 1.x 版本中使用
SparkContext
来初始化 Spark 应用程序。
- SparkSession:
SparkSession
是 Spark 2.x 版本中引入的新概念,它是 Spark SQL 的入口点,用于处理结构化数据。SparkSession
继承了SparkContext
的功能,同时还提供了对 DataFrame 和 SQL 查询的支持。- 它更加方便,允许你在一个会话中无缝地使用 Spark SQL、DataFrame 操作和原始 RDD 操作。
- 通过
SparkSession
,你可以创建和操作 DataFrame,执行 SQL 查询,以及与 Spark 集群交互。 - 在 Spark 2.x 及以后的版本中,通常建议使用
SparkSession
作为 Spark 应用程序的入口点。
在 Spark 2.x 及以后的版本中,你可以通过以下方式创建一个 SparkSession
:
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("MySparkApp").getOrCreate()
这将创建一个 SparkSession
,它将充当你的 Spark 应用程序的入口点,允许你同时使用 Spark SQL 和 Spark 原始操作。你可以使用这个 SparkSession
来加载数据、处理结构化数据,并执行 SQL 查询。 SparkSession
是更强大和更灵活的选项,特别是在处理结构化数据时。
实际上,在启动进入pyspark以后,pyspark就默认提供了一个SparkContext对象(名称为sc)和一个SparkSession对象(名称为spark)
SparkSession
并没有直接继承 SparkContext
,而是在 Spark 2.x 版本中引入的一种更高级、更综合的接口,它包含了 SparkContext
的功能,并进一步扩展了许多新功能,特别是在结构化数据处理方面。
简单来说处理rdd数据使用sparkcontext,别的推荐使用sparksession
总之,SparkSession
是 Spark 2.x 及以后版本的推荐入口点,它提供了更多的功能,特别是在处理结构化数据和执行 SQL 查询方面。虽然 SparkContext
仍然有其用途,但大多数情况下使用 SparkSession
更加方便,尤其是在处理和分析结构化数据时。所以,如果你使用的是 Spark 2.x 或更新版本,通常更建议使用 SparkSession
。
Spark SQL架构
Catalyst Optimizer:
- Parser:Spark SQL 首先将 SQL 查询字符串解析为抽象语法树(AST)。
- Analyzer:AST 经过分析,检查语法和语义错误,执行命名解析和类型检查,以准备进行优化。
- Logical Plan:在这个阶段,生成一个逻辑查询计划,表示查询的逻辑结构。
Tungsten Execution Engine:
- Optimization:Catalyst Optimizer 优化逻辑查询计划,应用各种优化规则,以提高查询性能。
- Physical Plan:生成物理查询计划,它指定了如何在分布式集群上执行查询。这包括选择数据分布和任务调度。
- Code Generation:Spark SQL 使用 Tungsten 代码生成技术,将物理计划转换为高效的 Java 字节码,以加速数据处理。
Data Sources:
- Spark SQL 可以连接多种数据源,包括关系型数据库、Parquet、Avro、JSON、CSV 等。数据源模块负责加载和解析数据,使其可用于查询。
Hive Integration:
- Spark SQL 集成了 Hive 元存储和查询功能,允许用户查询 Hive 表和使用 Hive UDFs(用户定义函数)。
DataFrame API:
- DataFrame API 提供了以编程方式处理数据的方法,类似于关系数据库中的表。DataFrame 可以通过编程方式创建、转换和操作,也可以与 SQL 查询一起使用。
User-Defined Functions (UDFs):
- 用户可以定义自己的函数,然后在 Spark SQL 查询中使用这些 UDFs。这允许用户扩展 Spark SQL 的功能以满足特定需求。
Query Execution:
- 查询执行引擎将物理计划转化为实际的分布式任务,并在 Spark 集群上执行这些任务。这包括数据的分布式处理、数据的分区和节点之间的数据传输。
Result Presentation:
- 查询结果可以以多种格式呈现,包括在控制台中显示、写入文件或写入外部系统。
Cluster Manager Integration:
- Spark SQL 可以与不同的集群管理器集成,如 Apache Hadoop YARN、Apache Mesos 或独立的 Spark 集群管理器。
DataFrame
dataframe,rdd区别
DataFrame:
DataFrame 是一种结构化数据抽象,类似于关系型数据库中的表格。它的特点如下:
列名和数据类型:
DataFrame 包含多个列,每个列都有一个名称和数据类型。这意味着 DataFrame 中的数据是按照表格形式组织的,每列的数据类型是明确的,例如整数、字符串、日期等。
模式信息:
DataFrame 通常具有一个明确的模式信息,描述了每列的名称和数据类型。这使得数据的结构变得清晰,有助于数据的解释和查询。
优化和查询:
DataFrame 支持高级的查询和操作,包括 SQL 查询、筛选、映射、分组、聚合等。它可以通过 Catalyst 查询优化器进行查询优化,以提高查询性能。
SQL 集成:
DataFrame 集成了 Spark SQL,可以使用 SQL 查询语言来查询和操作数据,使得处理结构化数据更加方便。
这个是dataframe的一个数据例子,这是类似表格的
+----+------+-----+
| ID | Name | Age |
+----+------+-----+
| 1 | Alice| 20 |
| 2 | Bob | 22 |
| 3 | Carol| 21 |
| 4 | David| 23 |
+----+------+-----+
RDD:
RDD(弹性分布式数据集)是一组分布在集群中的数据对象,它没有固定的结构,可以包含各种类型的数据。它的特点如下:
弱类型:
RDD 是弱类型的,它不包含列的名称和数据类型信息。这意味着你需要自己管理数据的类型转换和验证。
通用性:
RDD 可以包含各种类型的数据,包括结构化和非结构化数据。它没有固定的表格结构,可以适应不同类型的数据。
操作和转换:
RDD 提供了基本的操作和转换方法,如 map、reduce、filter 等。你需要手动编写代码来实现数据处理逻辑
数据管理:
RDD 需要手动管理分区、数据分布和数据处理过程。这通常需要更多的编程工作和手动优化。
rdd的数据类型就多种多样
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
由于rdd的弱类型,包含各种类型数据,dataframe中的数据也可以通过.rdd方法转换为rdd数据
概念
DataFrame 是一种表格型的数据结构,它被广泛用于数据存储和分析,特别是在Python的Pandas库、R语言以及Apache Spark等数据处理工具中。DataFrame 提供了一个二维的、表格式的数据结构,其中每列可以包含不同类型的数据(数值、字符串、布尔值等),类似于SQL表格或Excel电子表格。
在 Apache Spark 中的 DataFrame 是一个不可变的分布式数据集合,被设计用于处理大量的结构化数据。Spark 的 DataFrame 是在 RDD(Resilient Distributed Dataset,弹性分布式数据集)的基础上进一步封装,它提供了更加高级的抽象,以及针对结构化和半结构化数据的优化接口。
DataFrame 的关键特点包括:
- 结构化数据:DataFrame 是设计用于处理结构化数据,这意味着数据以表格的形式组织,包含行和列。每列都有一个名称和数据类型,每行包含具体的数据。这使得 DataFrame 适用于处理类似关系型数据库中的数据。
- 强类型:DataFrame 是强类型的,这意味着每列都具有明确的数据类型,例如整数、字符串、日期等。这有助于捕获和防止类型错误,使数据处理更加稳定和可维护。
- 不可变性:DataFrame 是不可变的,这意味着一旦创建,你不能直接修改它。任何对 DataFrame 的操作都会创建一个新的 DataFrame。这种不可变性有助于并发处理和避免数据损坏。
- 惰性求值:DataFrame 操作通常是惰性求值的,这意味着操作不会立即执行,而是在需要时才执行。这允许 Spark 进行优化和执行计划的生成,以提高性能。
- 分布式处理:DataFrame 允许你在分布式计算集群上处理数据。它可以自动将数据分割成分区,并在不同的节点上执行操作,从而实现高性能的数据处理。
- API 支持:Spark SQL 提供了多种编程语言的 API 支持,包括 Scala、Java、Python 和 R。你可以使用你最熟悉的编程语言来操作 DataFrame。
- 操作和转换:DataFrame 支持各种操作和转换,如筛选、映射、分组、聚合、连接、排序等。这些操作允许你进行复杂的数据处理和分析。
- 集成 Spark SQL:DataFrame 是 Spark SQL 的一部分,允许你使用 SQL 查询语言来查询和处理数据,也可以将 DataFrame 和 SQL 查询混合使用,从而更灵活地满足不同需求。
读取
在 Apache Spark 中创建 DataFrame 的过程通常涉及以下几个步骤:
- 初始化 SparkSession: SparkSession 是与 Spark 的交互入口。在开始使用 Spark 之前,需要创建一个 SparkSession 对象。
- 准备数据: 数据可以来源于本地集合(如 Python 列表)、外部数据源(如 HDFS、Hive 表、关系型数据库、JSON 文件等)。
- 创建 DataFrame: 使用 SparkSession 读取数据,将数据读取为 DataFrame 格式。对于本地集合,可以使用
spark.createDataFrame(data)
方法。
举一个具体的例子:
假设您有一个包含用户信息的列表,想要创建一个DataFrame。在 PySpark 中,您可以这样做:
from pyspark.sql import SparkSession
from pyspark.sql import Row
# 初始化 SparkSession
spark = SparkSession.builder.appName("ExampleApp").getOrCreate()
# 使用 Row 对象准备数据
data = [Row(name="Alice", age=12, grade=6),
Row(name="Bob", age=15, grade=9),
Row(name="Cindy", age=14, grade=8)]
# 使用 SparkSession 创建 DataFrame
df = spark.createDataFrame(data)
# 显示 DataFrame
df.show()
当运行上述代码时,df.show()
将以表格的形式输出 DataFrame 的内容。这是一个非常简单的示例,仅用于演示在 Spark 中创建 DataFrame 的过程。
在实际应用中,通常会从文件系统如 HDFS、云存储或者数据库中读取数据创建 DataFrame,示例如下:
# 读取 JSON 文件创建 DataFrame
df = spark.read.json("path/to/jsonfile.json")
# 读取 CSV 文件创建 DataFrame
df = spark.read.csv("path/to/csvfile.csv", inferSchema=True, header=True)
保存
在 PySpark 中,你可以使用 write
方法将 DataFrame 保存到不同的数据存储系统中。DataFrame 提供了多种保存格式的选项,包括 Parquet、JSON、CSV、Avro、JDBC 数据库等。以下是将 DataFrame 保存到不同格式的示例:
-
保存为 Parquet 文件:
df.write.parquet("data.parquet")
这将保存 DataFrame 为 Parquet 文件。
-
保存为 JSON 文件:
df.write.json("data.json")
这将保存 DataFrame 为 JSON 文件。
-
保存为 CSV 文件:
df.write.csv("data.csv")
这将保存 DataFrame 为 CSV 文件。
-
保存到 JDBC 数据库:
df.write \ .format("jdbc") \ .option("url", "jdbc:mysql://localhost:3306/database_name") \ .option("dbtable", "table_name") \ .option("user", "username") \ .option("password", "password") \ .save()
这将保存 DataFrame 到指定的 JDBC 数据库表中。
-
其他格式:Spark 提供了多种其他格式,你可以根据需要选择,如 Avro、ORC、Delta Lake 等。
Spark 会将结果写入目标目录,并以分区文件的方式保存数据。这是 Spark 处理数据的一种常见方式,尤其是在分布式环境中。
在写入 JSON 文件时,Spark 将数据按照默认分区方式进行划分,并将每个分区保存为一个 JSON 文件。所以你看到了 part-00000-3db90180-ec7c-4291-ad05-df8e45c77f4d.json 文件,它是一个分区文件,包含了一部分数据。同时,还有 _SUCCESS 文件,用于标记作业执行的成功。
目录中通常包含以下文件和内容:
数据文件:这些是存储实际数据的文件。每个分区生成一个数据文件,数据文件包含了分区中的数据记录。
元数据文件:在目录中可能会包含一些元数据文件,用于描述数据的结构、模式和其他信息。这些文件通常包括 .metadata 文件或 .crc 文件,用于检查数据完整性。
成功标记文件:通常会生成一个 _SUCCESS 文件,用于标记作业执行成功。这个文件通常是一个空文件,用于指示数据保存操作已成功完成。
下面是一个案例
mydata/
|-- part-00000-3db90180-ec7c-4291-ad05-df8e45c77f4d.json
|-- part-00001-7c3b459f-d5a2-4857-8a69-4417c1509e99.json
|-- .metadata
|-- _SUCCESS
反射机制推断RDD
要使用反射机制从 RDD 创建 DataFrame,RDD 本身的数据应该是结构化的,每个元素应该包含字段和数据类型的信息。具体来说,RDD 中的每个元素应该是一个结构化数据对象
from pyspark.sql import SparkSession
# 创建 SparkSession
spark = SparkSession.builder.appName("ReflectionExample").getOrCreate()
# 创建一个包含学生信息的结构化 RDD
student_data = [
{"name": "Alice", "age": 20},
{"name": "Bob", "age": 22},
{"name": "Carol", "age": 21},
{"name": "David", "age": 23}
]
# 将结构化数据创建为 RDD
rdd = spark.sparkContext.parallelize(student_data)
# 使用反射机制将 RDD 转换为 DataFrame
from pyspark.sql import Row
df = rdd.map(lambda x: Row(**x)).toDF()
# 显示 DataFrame 数据
df.show()
下面两行是转换dataframe的关键
rdd.map(lambda x: Row(**x))
: 在这一步中,map
操作对 RDD 中的每个元素执行一个函数,这个函数接受一个字典x
(即 RDD 中的元素),然后使用Row(**x)
将字典转换为Row
对象。这里Row
是 Spark SQL 中的一个特殊类,它允许将结构化数据转换为具有明确字段和数据类型的对象。toDF()
: 这一步将包含Row
对象的 RDD 转换为 DataFrame。此时,Spark 使用反射机制自动推断每个Row
对象中的字段名称和数据类型,并构建一个具有明确模式的 DataFrame。
row的介绍
pyspark.sql.Row
是 PySpark 中的一个类,用于创建和表示具有命名字段的数据记录。Row
类允许你创建具有明确字段名称的数据记录,通常在使用反射机制创建 DataFrame 时非常有用。
from pyspark.sql import Row
# 创建一个 Row 对象表示一个人的信息
person = Row(name="Alice", age=30, city="New York")
#在改行代码中已经确定了属性字段name,age,city
# 访问 Row 对象的字段
print(person.name) # 输出 "Alice"
print(person.age) # 输出 30
print(person.city) # 输出 "New York"
# 注册 DataFrame 为临时表
对象名字.createOrReplaceTempView("临时注册表名")
# 执行 SQL 查询
result = spark.sql("SELECT name, age FROM 临时注册表 WHERE age > 20")
#生成了临时注册表后,你可以将 DataFrame 视为一个数据表,可以使用 SQL 查询语法来操作它。这意味着你可以使用 SQL 查询来筛选、排序、聚合和转换数据,就像在关系型数据库中一样
编程式rdd推断
from pyspark.sql.types import *
#等价于from pyspark.sql.types import StructType, StructField, StringType, IntegerType
#使用 StructType 定义了模式,每个字段由 StructField 定义,指定字段名、数据类型以及是否允许为空(True 表示允许为空)
schema = StructType([
StructField("name", StringType(), True),
StructField("age", IntegerType(), True)
])
# 使用定义好的模式将数据转换为 DataFrame
df = spark.createDataFrame(
lines.map(lambda line: line.split(",")),
schema
)
#spark.createDataFrame(...): 这一部分使用 createDataFrame 方法来创建 DataFrame。它接受两个参数,第一个参数是分割后的数据,即文本数据的每行被分割为一个字符串列表,第二个参数是模式(schema),用于指定字段名称和数据类型。
#注意第一个参数是分割后的数据,通常是一个 RDD,其中每个元素表示一行数据,每行数据都被分割为一个字符串列表。第二个参数是数据模式(schema),它定义了字段名称和数据类型,用于确定如何解释和处理数据。
#第一个参数的数量必须要和第二个参数的数量对应,因为一个字段必须对应一个列第二个参数是数据模式(schema),它定义了字段名称和数据类型,用于确定如何解释和处理数据。
# 注册 DataFrame 为临时表
df.createOrReplaceTempView("people")
二者区别:
- 编程式 RDD 推断:
- 模式定义方式:在编程式 RDD 推断中,你需要手动定义模式,即字段名称和数据类型。这通常需要你在代码中明确指定每个字段的名称和类型,以确保数据被正确解释。
- 数据处理方式:你需要通过编程方式将数据映射到模式中的字段,确保数据和模式的一一对应。这种方式适用于处理结构未知的数据,或者在需要精确控制数据结构时使用。
- 反射式 RDD 推断:
- 模式定义方式:在反射式 RDD 推断中,模式是通过自动检测 RDD 中的数据来推断的,而不需要手动定义。系统会尝试从数据中推断出字段名称和数据类型。
- 数据处理方式:数据的结构是由系统自动推断的,你无需手动映射数据到模式中的字段。这种方式适用于已知数据结构并且希望快速创建 DataFrame 的情况。
总的来说,编程式 RDD 推断需要更多的手动工作,但允许更大的灵活性,适用于处理未知结构的数据。反射式 RDD 推断则更加自动化,适用于已知结构的数据,可以更快速地创建 DataFrame。选择哪种方式取决于数据的特性以及你的需求。
使用Spark SQL
-
创建 SparkSession:首先,你需要创建一个
SparkSession
对象,这是与 Spark SQL 交互的入口点。你可以使用以下方式创建:from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("MySparkSQLApp") \ .getOrCreate()
这将创建一个 SparkSession,它会为你提供对 Spark SQL 功能的访问。
-
加载数据:使用 SparkSession 来加载你的数据。你可以从各种数据源加载数据,如文本文件、CSV 文件、JSON 文件、Parquet 文件、数据库等。例如,要加载一个 CSV 文件:
df = spark.read.csv("data.csv", header=True, inferSchema=True)
这将创建一个 DataFrame 对象
df
,其中包含从 CSV 文件加载的数据。 -
执行 SQL 查询:你可以使用
spark.sql()
方法来执行 SQL 查询。例如:df.createOrReplaceTempView("mytable") # 创建一个临时视图 result = spark.sql("SELECT * FROM mytable WHERE age > 25") result.show()
这将执行 SQL 查询并显示结果。
-
进行 DataFrame 操作:除了执行 SQL 查询,你还可以使用 DataFrame API 进行各种操作,例如筛选、聚合、连接和转换数据。DataFrame API 提供了更灵活的方式来处理数据。
-
保存数据:如果需要,你可以将处理后的数据保存到不同的数据存储系统中,如 Parquet 文件、JSON 文件、数据库等。
-
关闭 SparkSession:在完成任务后,记得关闭 SparkSession 以释放资源:
spark.stop()
这些是 Spark SQL 的一般使用步骤。你可以根据具体的需求执行更复杂的操作,包括连接多个数据源、执行复杂的转换和分析,以及将结果保存到不同的数据存储系统中。确保你对 Spark SQL 和 PySpark 的文档有一定的了解,以更深入地了解它们的功能和用法。
连接数据库
jdbcDF = spark.read \
.format("jdbc") \
.option("driver","com.mysql.jdbc.Driver") \
.option("url","jdbc:mysql://localhost:3306/spark")\
.option("dbtable", "student") \
.option("user", "root") \
.option("password", "123456") \
.load()
jdbcDF.show()
下面是一个示例代码,展示如何使用 Spark SQL 向数据库写入数据。假设你已经有一个 DataFrame df
,并且你想将它写入名为 “mytable” 的数据库表:
from pyspark.sql import SparkSession
# 创建 SparkSession
spark = SparkSession.builder.appName("WriteToDatabase").getOrCreate()
# 创建一个 DataFrame df,包含要写入数据库的数据
# 数据库连接信息
url = "jdbc:mysql://localhost:3306/your_database"
properties = {
"user": "your_username",
"password": "your_password",
"driver": "com.mysql.jdbc.Driver"
}
# 写入数据到数据库表 "mytable"
# 写入模式,可以选择 "overwrite" 覆盖或 "append" 追加
df.write.mode("overwrite").jdbc(
url, "mytable",mode="overwrite", properties=properties)
# 关闭 SparkSession
spark.stop()
ppt的代码案例
#!/usr/bin/env python3
from pyspark.sql import Row
from pyspark.sql.types import *
from pyspark import SparkContext,SparkConf
from pyspark.sql import SparkSession
spark = SparkSession.builder.config(conf = SparkConf()).getOrCreate()
#下面设置模式信息
schema = StructType([StructField("id", IntegerType(), True), \
StructField("name", StringType(), True), \
StructField("gender", StringType(), True), \
StructField("age", IntegerType(), True)])
#下面设置两条数据,表示两个学生的信息
studentRDD = spark \
.sparkContext \
.parallelize(["3 Rongcheng M 26","4 Guanhua M 27"]) \
.map(lambda x:x.split(" "))
#下面创建Row对象,每个Row对象都是rowRDD中的一行
rowRDD = studentRDD.map(lambda p:Row(int(p[0].strip()), p[1].strip(), p[2].strip(), int(p[3].strip())))
#建立起Row对象和模式之间的对应关系,也就是把数据和模式对应起来
studentDF = spark.createDataFrame(rowRDD, schema)
#写入数据库
prop = {}
prop['user'] = 'root'
prop['password'] = '123456'
prop['driver'] = "com.mysql.jdbc.Driver"
studentDF.write.jdbc("jdbc:mysql://localhost:3306/spark",'student','append', prop)
请看的解释studentDF.write.jdbc(“jdbc:mysql://localhost:3306/spark”,‘student’,‘append’, prop)
jdbc
:这部分指定了使用 JDBC 协议来连接数据库。mysql
:这是数据库的类型,指定了要连接的数据库类型,这里是 MySQL。localhost
:这是数据库服务器的主机名或 IP 地址,表示连接到本地的数据库服务器。3306
:这是 MySQL 数据库的默认端口号,表示连接到 MySQL 服务器的 3306 端口。spark
:这部分是数据库的名称,表示要连接的数据库名称。在这里,它连接到名为 “spark” 的数据库。
所以,jdbc:mysql://localhost:3306/spark
表示将使用 JDBC 协议连接到本地 MySQL 数据库服务器的 “spark” 数据库。你可以根据实际情况修改这个连接字符串,将主机名、端口号、数据库名称等信息替换为你要连接的数据库服务器的信息。