spark SQL

spark SQL 概述

Spark SQL是Apache Spark的用于处理结构化数据的模块。强调的是"结构化数据",而非"SQL"

Spark SQL 提供的操作数据的方式

  • SQL
  • DataFrame API
  • Dataset API

集成

将SQL查询与Spark程序无缝混合。

Spark SQL使您可以使用SQL或熟悉的DataFrame API在Spark程序中查询结构化数据。可在Java,Scala,Python和R中使用。

results = spark.sql("SELECT * FROM people")
names = results.map(lambda p: p.name)

将函数应用于SQL查询的结果。

统一数据访问

以相同的方式连接到任何数据源。

DataFrame和SQL提供了一种访问各种数据源的通用方法,包括Hive,Avro,Parquet,ORC,JSON和JDBC。您甚至可以跨这些源连接数据。

spark.read.json("s3n://...").registerTempTable("json")
results = spark.sql(
  """SELECT *
     FROM people
     JOIN json ...""")

Hive整合

在现有仓库上运行SQL或HiveQL查询。

Spark SQL支持HiveQL语法以及Hive SerDes和UDF,从而使您可以访问现有的Hive仓库。

标准连接

通过JDBC或ODBC连接。

服务器模式为商业智能工具提供了行业标准的JDBC和ODBC连接。

spark SQL 架构

l  core处理数据的输入输出,从不同的数据源获取数据(RDD、Parquet、json等),将查询结果输出成schemaRDD;

l  catalyst处理查询语句的整个处理过程,包括解析、绑定、优化、物理计划等,说其是优化器,还不如说是查询引擎;

l  hive对hive数据的处理

l  hive-ThriftServer提供CLI和JDBC/ODBC接口

在这四个模块中,catalyst处于最核心的部分,其性能优劣将影响整体的性能。由于发展时间尚短,还有很多不足的地方,但其插件式的设计,为未来的发展留下了很大的空间。下面是catalyst的一个设计图:

其中虚线部分是以后版本要实现的功能,实线部分是已经实现的功能。从上图看,catalyst主要的实现组件有:

lsqlParse,完成sql语句的语法解析功能,目前只提供了一个简单的sql解析器;

lAnalyzer,主要完成绑定工作,将不同来源的Unresolved LogicalPlan和数据元数据(如hive metastore、Schema catalog)进行绑定,生成resolved LogicalPlan;

loptimizer对resolved LogicalPlan进行优化,生成optimized LogicalPlan;

l Planner将LogicalPlan转换成PhysicalPlan;

l CostModel,主要根据过去的性能统计数据,选择最佳的物理执行计划

这些组件的基本实现方法:

l 先将sql语句通过解析生成Tree,然后在不同阶段使用不同的Rule应用到Tree上,通过转换完成各个组件的功能。

l Analyzer使用Analysis Rules,配合数据元数据(如hive metastore、Schema catalog),完善Unresolved LogicalPlan的属性而转换成resolved LogicalPlan;

l optimizer使用Optimization Rules,对resolved LogicalPlan进行合并、列裁剪、过滤器下推等优化作业而转换成optimized LogicalPlan;

l Planner使用Planning Strategies,对optimized LogicalPlan

Datasets and DataFrames 

DataFrames:开发单机版应用程序一样来开发分布式应用程序

Datasets是数据的分布式集合。数据集是Spark 1.6中添加的新接口,它具有RDD的优点(强类型输入,使用强大的lambda函数的能力)以及Spark SQL的优化执行引擎的优点。数据集可以被构造从JVM对象,然后使用功能性的转换(操作mapflatMapfilter等等)。Dataset API在Scala和 Java中可用。Python不支持Dataset API。但是由于Python的动态特性,Dataset API的许多优点已经可用(即,您可以自然地通过名称访问行的字段 row.columnName)。R的情况类似。

DataFrame是组织为命名列的数据集(以列(列名、列类型、列值)的形式构成分布式的数据集)。从概念上讲,它等效于关系数据库中的表或R / Python中的数据框,但是在后台进行了更丰富的优化。可以从多种来源构造DataFrame,例如:结构化数据文件,Hive中的表,外部数据库或现有RDD。DataFrame API在Scala,Java,PythonR中可用。在Scala和Java中,DataFrame由的数据集表示Row。在Scala API中DataFrame只是类型别名Dataset[Row]。而在Java API中,用户需要使用Dataset<Row>来代表DataFrame

 

RDD和DF的区别

上图直观地体现了DataFrame和RDD的区别。

左侧的RDD[Person]虽然以Person为类型参数,但Spark框架本身不了解Person类的内部结构。而右侧的DataFrame却提供了详细的结构信息,使得Spark SQL可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。DataFrame多了数据的结构信息,即schema。

RDD是分布式的Java对象的集合。DataFrame是分布式的Row对象的集合。

DataFrame除了提供了比RDD更丰富的算子以外,更重要的特点是提升执行效率、减少数据读取以及执行计划的优化,比如filter下推、裁剪等。(DataFrame比RDD的执行效率要高一点,因为在大数据的处理中,RDD即使用mappartition或者foreachRDD都要消耗不少的core,但是DataFrame他可以进行sql操作,先过滤掉一部分数据,在RDD中是不好实现的。)

from pyspark.sql import SparkSession,Row
from pyspark.sql.types import LongType,StringType,StructField,StructType
if __name__=="__main__":

    spark=SparkSession.builder.appName("spark0801").getOrCreate()

    # df = spark.read.json("file:///opt/modules/spark-2.4.4-bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.json")
    # Displays the content of the DataFrame to stdout
    # df.printSchema()
    # df.select("name").show()
    # df.select(df.name,df.age+1).show()
    # df.filter(df.age>29).show()
    # df.groupBy("age").count().show()
    # df.createOrReplaceTempView("people")
    sc = spark.sparkContext
    df= sc.textFile("file:///opt/modules/spark-2.4.4-bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.txt")
    # lines=df.map(lambda x:x.split(",")).map(lambda p:Row(name=p[0],age=p[1].strip()))
    # print(lines.collect())
    # people=spark.createDataFrame(lines)

    lines=df.map(lambda x:x.split(",")).map(lambda p:(p[0],int(p[1].strip())))
    Struct_Fields=[StructField("name",StringType(),True),StructField("age",LongType(),True)]
    st=StructType(Struct_Fields)
    people=spark.createDataFrame(lines,st)
    people.createOrReplaceTempView("people")

    sql_people=spark.sql("select * from people where age=30")
    sql_people.show()
    print(sql_people.rdd.collect())
    spark.stop()
    # try:
    #     # df=spark.read.load("file:///opt/modules/spark-2.4.4-bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet")
    #     # df.select("name","favorite_numbers").show()
    #     # df=spark.read.load("file:///opt/modules/spark-2.4.4-bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.json", format="json")
    #     # df.select("name", "age").write.save("file:///opt/datas/namesAndAges.parquet",format='parquet',mode="append")
    #     # spark.sql("select * from parquet.`file:///opt/datas/namesAndAges.parquet`").show()
    #     df = spark.read.load("file:///opt/modules/spark-2.4.4-bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.csv",
    #                          format="csv", sep=";", inferSchema="true", header="true")
    #     df.show()
    # except Exception as e :
    #     print(f"出错了,{e}")
    # finally:
    #     spark.stop()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值