SparkSQL的整体实现逻辑解析
1、sql语句的模块解析
当我们写⼀个查询语句时,⼀般包含三个部分,select部分,from数据源部分,where限制条件部分,这三部分的内容在sql 中有专门的名称:
当我们写sql时,如上图所⽰,在进⾏逻辑解析时会把sql分成三个部分,project,DataSource,Filter模块,当⽣成执⾏部分时⼜把他们称为:Result模块、
DataSource模块和Opertion模块。
那么在关系数据库中,当我们写完⼀个查询语句进⾏执⾏时,发⽣的过程如下图所⽰:
整个执⾏流程是:query -> Parse -> Bind -> Optimize -> Execute
1、写完sql查询语句,sql的查询引擎⾸先把我们的查询语句进⾏解析,也就是Parse过程,解析的过程是把我们写的查询语句进⾏分割,把project,DataSource和Filter三个部分解析出来从⽽形成⼀个逻辑解析tree,在解析的过程中还会检查我们的sql 语法是否有错误,⽐如缺少指标字段、数据库中不包含这张数据表等。当发现有错误时⽴即停⽌解析,并报错。当顺利完成解析时,会进⼊到Bind过程。
2、Bind过程,通过单词我们可看出,这个过程是⼀个绑定的过程。为什么需要绑定过程?这个问题需要我们从软件实现的⾓度去思考,如果让我们来实现这个sql查询引擎,我们应该怎么做?他们采⽤的策略是⾸先把sql查询语句分割,分割不同的部分,再进⾏解析从⽽形成逻辑解析tree,然后需要知道我们需要取数据的数据表在哪⾥,需要哪些字段,执⾏什么逻辑,这些都保存在数据库的数据字典中,因此bind过程,其实就是把Parse过程后形成的逻辑解析tree,与数据库的数据字典绑定的过程。绑定后会形成⼀个执⾏tree,从⽽让程序知道表在哪⾥,需要什么字段等等
3、完成了Bind过程后,数据库查询引擎会提供⼏个查询执⾏计划,并且给出了查询执⾏计划的⼀些统
计信息,既然提供了⼏个执⾏计划,那么有⽐较就有优劣,数据库会根据这些执⾏计划的统计信息选择⼀个最优的执⾏计划,因此这个过程是Optimize(优化)过程。
4、选择了⼀个最优的执⾏计划,那么就剩下最后⼀步执⾏Execute,最后执⾏的过程和我们解析的过程是不⼀样的,当我们知道执⾏的顺序,对我们以后写sql以及优化都是有很⼤的帮助的.执⾏查询后,他是先执⾏where部分,然后到数据源之数据表,最后⽣成select的部分,我们的最终结果。执⾏的顺序是:operation->DataSource->Result
虽然以上部分对SparkSQL没有什么联系,但是知道这些,对我们理解SparkSQL还是很有帮助的。
2、SparkSQL框架的架构
要想对这个框架有⼀个清晰的认识,⾸先我们要弄清楚,我们为什么需要sparkSQL呢?个⼈建议⼀般情况下在写sql能够直接解决的问题就不要使⽤sparkSQL,如果想刻意使⽤sparkSQL,也不⼀定能够加快开发的进程。使⽤sparkSQL是为了解决⼀般⽤sql不能解决的复杂逻辑,使⽤编程语⾔的优势来解决问题。我们使⽤sparkSQL⼀般的流程如下图:
如上图所⽰,⼀般情况下分为两个部分:a、把数据读⼊到sparkSQL中,sparkSQL进⾏数据处理或者算法实现,然后再把处理后的数据输出到相应的输出源中。
1、同样我们也是从如果让我们开发,我们应该怎么做,需要考虑什么问题来思考这个问题。
a、第⼀个问题是,数据源有⼏个,我们可能从哪些数据源读取数据?现在sparkSQL⽀持很多的数据源,⽐如:hive数据仓库、json⽂件,.txt,以及orc⽂件,同时现在还⽀持jdbc从关系数据库中取数据。功能很强⼤。
b、还⼀个需要思考的问题是数据类型怎么映射啊?我们知道当我们从⼀个数据库表中读⼊数据时,我们定义的表结构的字段的类型和编程语⾔⽐如scala中的数据类型映射关系是怎样的⼀种映射关系?在sparkSQL中有⼀种来解决这个问题的⽅法,来实现数据表中的字段类型到编程语⾔数据类型的映射关系。这个以后详细介绍,先了解有这个问题就⾏。
c、数据有了,那么在sparkSQL中我们应该怎么组织这些数据,需要什么样的数据结构呢,同时我们对这些数据都可以进⾏什么样的操作?sparkSQL采⽤的是DataFrame数据结构来组织读⼊到sparkSQL中的数据,DataFrame数据结构其实和数据库的表结构差不多,数据是按照⾏来进⾏存储,同是还有⼀个schema,就相当于数据库的表结构,记录着每⼀⾏数据属于哪个字段。
d、当数据处理完以后,我们需要把数据放⼊到什么地⽅,并切以什么样的格式进⾏对应,这个a和b要解决的问题是相同的。
2、sparkSQL对于以上问题的实现逻辑也很明确,从上图已经很清楚,主要分为两个阶段,每个阶段都对应⼀个具体的类来实现。
a、对于第⼀个阶段,sparkSQL中存在两个类来解决这些问题:HiveContext,SQLContext,同时hiveContext继承了SQLContext的所有⽅法,同时⼜对其进⾏了扩展。因为我们知道, hive和mysql的查询还是有⼀定的差别的。HiveContext只是⽤来处理从hive数据仓库中读⼊数据的操作,SQLContext可以处理sparkSQL能够⽀持的剩下的所有的数据源。这两个类处理的粒度是限制在对数据的读写上,同时对表级别的操作上,⽐如,读⼊数据、缓存表、释放缓存表表、注册表、删除注册的表、返回表的结构等的操作。
b、sparkSQL处理读⼊的数据,采⽤的是DataFrame中提供的⽅法。因为当我们把数据读⼊到sparkSQL中,这个数据就是DataFrame类型的。同时数据都是按照Row进⾏存储的。其中 DataFrame中提供了很多有⽤的⽅法。以后会细说。
c、在spark1.6版本以后,⼜增加了⼀个类似于DataFrame的数据结构Dataset,增加此数据结构的⽬的是DataFrame有软肋,他只能处理按照Row进⾏存储的数据,并且只能使⽤DataFrame中提供的⽅法,我们只能使⽤⼀部分RDD提供的操作。实现Dataset的⽬的就是让我们能够像操作RDD⼀样来操作sparkSQL中的数据。
d、其中还有⼀些其他的类,但是现在在sparkSQL中最主要的就是上⾯的三个类,其他类以后碰到了会慢慢想清楚。
3、sparkSQL的hiveContext和SQLContext的运⾏原理
hiveContext和SQLContext与我第⼀部分讲到的sql语句的模块解析实现的原理其实是⼀样的,采⽤了同样的逻辑过程,并且⽹上有好多讲这⼀块的,就直接粘贴复制啦!!
sqlContext总的⼀个过程如下图所⽰:
1.SQL语句经过SqlParse解析成UnresolvedLogicalPlan;
2.使⽤analyzer结合数据数据字典(catalog)进⾏绑定,⽣成resolvedLogicalPlan;
3.使⽤optimizer对resolvedLogicalPlan进⾏优化,⽣成optimizedLogicalPlan;
4.使⽤SparkPlan将LogicalPlan转换成PhysicalPlan;
5.使⽤prepareForExecution()将PhysicalPlan转换成可执⾏物理计划;
6.使⽤execute()执⾏可执⾏物理计划;
7.⽣成SchemaRDD。
在整个运⾏过程中涉及到多个SparkSQL的组件,如SqlParse、analyzer、optimizer、SparkPlan等等
hiveContext总的⼀个过程如下图所⽰:
1.SQL语句经过HiveQl.parseSql解析成Unresolved LogicalPlan,在这个解析过程中对hiveql语句使⽤getAst()获取AST树,然后再进⾏解析;
2.使⽤analyzer结合数据hive、源数据Metastore(新的catalog)进⾏绑定,⽣成resolved LogicalPlan;
sql包含哪几个部分3.使⽤optimizer对resolved LogicalPlan进⾏优化,⽣成optimized LogicalPlan,优化前使⽤了
ExtractPythonUdfs(catalog.PreInsertionCasts(catalog.CreateTables(analyzed)))进⾏预处理;
4.使⽤hivePlanner将LogicalPlan转换成PhysicalPlan;
5.使⽤prepareForExecution()将PhysicalPlan转换成可执⾏物理计划;
6.使⽤execute()执⾏可执⾏物理计划;
7.执⾏后,使⽤map(_.copy)将结果导⼊SchemaRDD。
到此这篇关于Spark SQL的整体实现逻辑的⽂章就介绍到这了,更多相关Spark SQL实现逻辑内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论