dataframe与saprkSQL的概念与操作

sparkSQL背景

  1. sparkContext:
    • SparkContext 是 Spark 应用程序的入口点,它代表了与 Spark 集群的连接。
    • 它是 Spark 1.x 版本中的主要入口点,在 Spark 2.x 版本中引入了 SparkSession 来替代 SparkContext
    • SparkContext 负责管理任务调度、数据分区和与集群的通信。
    • 你可以使用 SparkContext 来创建 RDD(弹性分布式数据集)并执行基本的 Spark 操作,例如 map、reduce 等。
    • 通常,你会在 Spark 1.x 版本中使用 SparkContext 来初始化 Spark 应用程序。
  2. 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 的过程通常涉及以下几个步骤:

  1. 初始化 SparkSession: SparkSession 是与 Spark 的交互入口。在开始使用 Spark 之前,需要创建一个 SparkSession 对象。
  2. 准备数据: 数据可以来源于本地集合(如 Python 列表)、外部数据源(如 HDFS、Hive 表、关系型数据库、JSON 文件等)。
  3. 创建 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 保存到不同格式的示例:

  1. 保存为 Parquet 文件

    df.write.parquet("data.parquet")
    

    这将保存 DataFrame 为 Parquet 文件。

  2. 保存为 JSON 文件

    df.write.json("data.json")
    

    这将保存 DataFrame 为 JSON 文件。

  3. 保存为 CSV 文件

    df.write.csv("data.csv")
    

    这将保存 DataFrame 为 CSV 文件。

  4. 保存到 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 数据库表中。

  5. 其他格式: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的关键

  1. rdd.map(lambda x: Row(**x)): 在这一步中,map 操作对 RDD 中的每个元素执行一个函数,这个函数接受一个字典 x(即 RDD 中的元素),然后使用 Row(**x) 将字典转换为 Row 对象。这里 Row 是 Spark SQL 中的一个特殊类,它允许将结构化数据转换为具有明确字段和数据类型的对象。
  2. 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")

二者区别:

  1. 编程式 RDD 推断:
    • 模式定义方式:在编程式 RDD 推断中,你需要手动定义模式,即字段名称和数据类型。这通常需要你在代码中明确指定每个字段的名称和类型,以确保数据被正确解释。
    • 数据处理方式:你需要通过编程方式将数据映射到模式中的字段,确保数据和模式的一一对应。这种方式适用于处理结构未知的数据,或者在需要精确控制数据结构时使用。
  2. 反射式 RDD 推断:
    • 模式定义方式:在反射式 RDD 推断中,模式是通过自动检测 RDD 中的数据来推断的,而不需要手动定义。系统会尝试从数据中推断出字段名称和数据类型。
    • 数据处理方式:数据的结构是由系统自动推断的,你无需手动映射数据到模式中的字段。这种方式适用于已知数据结构并且希望快速创建 DataFrame 的情况。

总的来说,编程式 RDD 推断需要更多的手动工作,但允许更大的灵活性,适用于处理未知结构的数据。反射式 RDD 推断则更加自动化,适用于已知结构的数据,可以更快速地创建 DataFrame。选择哪种方式取决于数据的特性以及你的需求。

使用Spark SQL

  1. 创建 SparkSession:首先,你需要创建一个 SparkSession 对象,这是与 Spark SQL 交互的入口点。你可以使用以下方式创建:

    from pyspark.sql import SparkSession
    spark = SparkSession.builder \
        .appName("MySparkSQLApp") \
        .getOrCreate()
    

    这将创建一个 SparkSession,它会为你提供对 Spark SQL 功能的访问。

  2. 加载数据:使用 SparkSession 来加载你的数据。你可以从各种数据源加载数据,如文本文件、CSV 文件、JSON 文件、Parquet 文件、数据库等。例如,要加载一个 CSV 文件:

    df = spark.read.csv("data.csv", header=True, inferSchema=True)
    

    这将创建一个 DataFrame 对象 df,其中包含从 CSV 文件加载的数据。

  3. 执行 SQL 查询:你可以使用 spark.sql() 方法来执行 SQL 查询。例如:

    df.createOrReplaceTempView("mytable")  # 创建一个临时视图
    result = spark.sql("SELECT * FROM mytable WHERE age > 25")
    result.show()
    

    这将执行 SQL 查询并显示结果。

  4. 进行 DataFrame 操作:除了执行 SQL 查询,你还可以使用 DataFrame API 进行各种操作,例如筛选、聚合、连接和转换数据。DataFrame API 提供了更灵活的方式来处理数据。

  5. 保存数据:如果需要,你可以将处理后的数据保存到不同的数据存储系统中,如 Parquet 文件、JSON 文件、数据库等。

  6. 关闭 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” 数据库。你可以根据实际情况修改这个连接字符串,将主机名、端口号、数据库名称等信息替换为你要连接的数据库服务器的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值