Spark SQL的整體實(shí)現(xiàn)邏輯解析
1、sql語(yǔ)句的模塊解析
當(dāng)我們寫(xiě)一個(gè)查詢語(yǔ)句時(shí),一般包含三個(gè)部分,select部分,from數(shù)據(jù)源部分,where限制條件部分,這三部分的內(nèi)容在sql中有專(zhuān)門(mén)的名稱:
當(dāng)我們寫(xiě)sql時(shí),如上圖所示,在進(jìn)行邏輯解析時(shí)會(huì)把sql分成三個(gè)部分,project,DataSource,F(xiàn)ilter模塊,當(dāng)生成執(zhí)行部分時(shí)又把他們稱為:Result模塊、
DataSource模塊和Opertion模塊。
那么在關(guān)系數(shù)據(jù)庫(kù)中,當(dāng)我們寫(xiě)完一個(gè)查詢語(yǔ)句進(jìn)行執(zhí)行時(shí),發(fā)生的過(guò)程如下圖所示:
整個(gè)執(zhí)行流程是:query -> Parse -> Bind -> Optimize -> Execute
1、寫(xiě)完sql查詢語(yǔ)句,sql的查詢引擎首先把我們的查詢語(yǔ)句進(jìn)行解析,也就是Parse過(guò)程,解析的過(guò)程是把我們寫(xiě)的查詢語(yǔ)句進(jìn)行分割,把project,DataSource和Filter三個(gè)部分解析出來(lái)從而形成一個(gè)邏輯解析tree,在解析的過(guò)程中還會(huì)檢查我們的sql語(yǔ)法是否有錯(cuò)誤,比如缺少指標(biāo)字段、數(shù)據(jù)庫(kù)中不包含這張數(shù)據(jù)表等。當(dāng)發(fā)現(xiàn)有錯(cuò)誤時(shí)立即停止解析,并報(bào)錯(cuò)。當(dāng)順利完成解析時(shí),會(huì)進(jìn)入到Bind過(guò)程。
2、Bind過(guò)程,通過(guò)單詞我們可看出,這個(gè)過(guò)程是一個(gè)綁定的過(guò)程。為什么需要綁定過(guò)程?這個(gè)問(wèn)題需要我們從軟件實(shí)現(xiàn)的角度去思考,如果讓我們來(lái)實(shí)現(xiàn)這個(gè)sql查詢引擎,我們應(yīng)該怎么做?他們采用的策略是首先把sql查詢語(yǔ)句分割,分割不同的部分,再進(jìn)行解析從而形成邏輯解析tree,然后需要知道我們需要取數(shù)據(jù)的數(shù)據(jù)表在哪里,需要哪些字段,執(zhí)行什么邏輯,這些都保存在數(shù)據(jù)庫(kù)的數(shù)據(jù)字典中,因此bind過(guò)程,其實(shí)就是把Parse過(guò)程后形成的邏輯解析tree,與數(shù)據(jù)庫(kù)的數(shù)據(jù)字典綁定的過(guò)程。綁定后會(huì)形成一個(gè)執(zhí)行tree,從而讓程序知道表在哪里,需要什么字段等等
3、完成了Bind過(guò)程后,數(shù)據(jù)庫(kù)查詢引擎會(huì)提供幾個(gè)查詢執(zhí)行計(jì)劃,并且給出了查詢執(zhí)行計(jì)劃的一些統(tǒng)計(jì)信息,既然提供了幾個(gè)執(zhí)行計(jì)劃,那么有比較就有優(yōu)劣,數(shù)據(jù)庫(kù)會(huì)根據(jù)這些執(zhí)行計(jì)劃的統(tǒng)計(jì)信息選擇一個(gè)最優(yōu)的執(zhí)行計(jì)劃,因此這個(gè)過(guò)程是Optimize(優(yōu)化)過(guò)程。
4、選擇了一個(gè)最優(yōu)的執(zhí)行計(jì)劃,那么就剩下最后一步執(zhí)行Execute,最后執(zhí)行的過(guò)程和我們解析的過(guò)程是不一樣的,當(dāng)我們知道執(zhí)行的順序,對(duì)我們以后寫(xiě)sql以及優(yōu)化都是有很大的幫助的.執(zhí)行查詢后,他是先執(zhí)行where部分,然后找到數(shù)據(jù)源之?dāng)?shù)據(jù)表,最后生成select的部分,我們的最終結(jié)果。執(zhí)行的順序是:operation->DataSource->Result
雖然以上部分對(duì)SparkSQL沒(méi)有什么聯(lián)系,但是知道這些,對(duì)我們理解SparkSQL還是很有幫助的。
2、SparkSQL框架的架構(gòu)
要想對(duì)這個(gè)框架有一個(gè)清晰的認(rèn)識(shí),首先我們要弄清楚,我們?yōu)槭裁葱枰猻parkSQL呢?個(gè)人建議一般情況下在寫(xiě)sql能夠直接解決的問(wèn)題就不要使用sparkSQL,如果想刻意使用sparkSQL,也不一定能夠加快開(kāi)發(fā)的進(jìn)程。使用sparkSQL是為了解決一般用sql不能解決的復(fù)雜邏輯,使用編程語(yǔ)言的優(yōu)勢(shì)來(lái)解決問(wèn)題。我們使用sparkSQL一般的流程如下圖:
如上圖所示,一般情況下分為兩個(gè)部分:a、把數(shù)據(jù)讀入到sparkSQL中,sparkSQL進(jìn)行數(shù)據(jù)處理或者算法實(shí)現(xiàn),然后再把處理后的數(shù)據(jù)輸出到相應(yīng)的輸出源中。
1、同樣我們也是從如果讓我們開(kāi)發(fā),我們應(yīng)該怎么做,需要考慮什么問(wèn)題來(lái)思考這個(gè)問(wèn)題。
a、第一個(gè)問(wèn)題是,數(shù)據(jù)源有幾個(gè),我們可能從哪些數(shù)據(jù)源讀取數(shù)據(jù)?現(xiàn)在sparkSQL支持很多的數(shù)據(jù)源,比如:hive數(shù)據(jù)倉(cāng)庫(kù)、json文件,.txt,以及orc文件,同時(shí)現(xiàn)在還支持jdbc從關(guān)系數(shù)據(jù)庫(kù)中取數(shù)據(jù)。功能很強(qiáng)大。
b、還一個(gè)需要思考的問(wèn)題是數(shù)據(jù)類(lèi)型怎么映射???我們知道當(dāng)我們從一個(gè)數(shù)據(jù)庫(kù)表中讀入數(shù)據(jù)時(shí),我們定義的表結(jié)構(gòu)的字段的類(lèi)型和編程語(yǔ)言比如scala中的數(shù)據(jù)類(lèi)型映射關(guān)系是怎樣的一種映射關(guān)系?在sparkSQL中有一種來(lái)解決這個(gè)問(wèn)題的方法,來(lái)實(shí)現(xiàn)數(shù)據(jù)表中的字段類(lèi)型到編程語(yǔ)言數(shù)據(jù)類(lèi)型的映射關(guān)系。這個(gè)以后詳細(xì)介紹,先了解有這個(gè)問(wèn)題就行。
c、數(shù)據(jù)有了,那么在sparkSQL中我們應(yīng)該怎么組織這些數(shù)據(jù),需要什么樣的數(shù)據(jù)結(jié)構(gòu)呢,同時(shí)我們對(duì)這些數(shù)據(jù)都可以進(jìn)行什么樣的操作?sparkSQL采用的是DataFrame數(shù)據(jù)結(jié)構(gòu)來(lái)組織讀入到sparkSQL中的數(shù)據(jù),DataFrame數(shù)據(jù)結(jié)構(gòu)其實(shí)和數(shù)據(jù)庫(kù)的表結(jié)構(gòu)差不多,數(shù)據(jù)是按照行來(lái)進(jìn)行存儲(chǔ),同是還有一個(gè)schema,就相當(dāng)于數(shù)據(jù)庫(kù)的表結(jié)構(gòu),記錄著每一行數(shù)據(jù)屬于哪個(gè)字段。
d、當(dāng)數(shù)據(jù)處理完以后,我們需要把數(shù)據(jù)放入到什么地方,并切以什么樣的格式進(jìn)行對(duì)應(yīng),這個(gè)a和b要解決的問(wèn)題是相同的。
2、sparkSQL對(duì)于以上問(wèn)題的實(shí)現(xiàn)邏輯也很明確,從上圖已經(jīng)很清楚,主要分為兩個(gè)階段,每個(gè)階段都對(duì)應(yīng)一個(gè)具體的類(lèi)來(lái)實(shí)現(xiàn)。
a、 對(duì)于第一個(gè)階段,sparkSQL中存在兩個(gè)類(lèi)來(lái)解決這些問(wèn)題:HiveContext,SQLContext,同時(shí)hiveContext繼承了SQLContext的所有方法,同時(shí)又對(duì)其進(jìn)行了擴(kuò)展。因?yàn)槲覀冎溃?hive和mysql的查詢還是有一定的差別的。HiveContext只是用來(lái)處理從hive數(shù)據(jù)倉(cāng)庫(kù)中讀入數(shù)據(jù)的操作,SQLContext可以處理sparkSQL能夠支持的剩下的所有的數(shù)據(jù)源。這兩個(gè)類(lèi)處理的粒度是限制在對(duì)數(shù)據(jù)的讀寫(xiě)上,同時(shí)對(duì)表級(jí)別的操作上,比如,讀入數(shù)據(jù)、緩存表、釋放緩存表表、注冊(cè)表、刪除注冊(cè)的表、返回表的結(jié)構(gòu)等的操作。
b、sparkSQL處理讀入的數(shù)據(jù),采用的是DataFrame中提供的方法。因?yàn)楫?dāng)我們把數(shù)據(jù)讀入到sparkSQL中,這個(gè)數(shù)據(jù)就是DataFrame類(lèi)型的。同時(shí)數(shù)據(jù)都是按照Row進(jìn)行存儲(chǔ)的。其中 DataFrame中提供了很多有用的方法。以后會(huì)細(xì)說(shuō)。
c、在spark1.6版本以后,又增加了一個(gè)類(lèi)似于DataFrame的數(shù)據(jù)結(jié)構(gòu)Dataset,增加此數(shù)據(jù)結(jié)構(gòu)的目的是DataFrame有軟肋,他只能處理按照Row進(jìn)行存儲(chǔ)的數(shù)據(jù),并且只能使用DataFrame中提供的方法,我們只能使用一部分RDD提供的操作。實(shí)現(xiàn)Dataset的目的就是讓我們能夠像操作RDD一樣來(lái)操作sparkSQL中的數(shù)據(jù)。
d、其中還有一些其他的類(lèi),但是現(xiàn)在在sparkSQL中最主要的就是上面的三個(gè)類(lèi),其他類(lèi)以后碰到了會(huì)慢慢想清楚。
3、sparkSQL的hiveContext和SQLContext的運(yùn)行原理
hiveContext和SQLContext與我第一部分講到的sql語(yǔ)句的模塊解析實(shí)現(xiàn)的原理其實(shí)是一樣的,采用了同樣的邏輯過(guò)程,并且網(wǎng)上有好多講這一塊的,就直接粘貼復(fù)制啦!!
sqlContext總的一個(gè)過(guò)程如下圖所示:
1.SQL語(yǔ)句經(jīng)過(guò)SqlParse解析成UnresolvedLogicalPlan;
2.使用analyzer結(jié)合數(shù)據(jù)數(shù)據(jù)字典(catalog)進(jìn)行綁定,生成resolvedLogicalPlan;
3.使用optimizer對(duì)resolvedLogicalPlan進(jìn)行優(yōu)化,生成optimizedLogicalPlan;
4.使用SparkPlan將LogicalPlan轉(zhuǎn)換成PhysicalPlan;
5.使用prepareForExecution()將PhysicalPlan轉(zhuǎn)換成可執(zhí)行物理計(jì)劃;
6.使用execute()執(zhí)行可執(zhí)行物理計(jì)劃;
7.生成SchemaRDD。
在整個(gè)運(yùn)行過(guò)程中涉及到多個(gè)SparkSQL的組件,如SqlParse、analyzer、optimizer、SparkPlan等等
hiveContext總的一個(gè)過(guò)程如下圖所示:
1.SQL語(yǔ)句經(jīng)過(guò)HiveQl.parseSql解析成Unresolved LogicalPlan,在這個(gè)解析過(guò)程中對(duì)hiveql語(yǔ)句使用getAst()獲取AST樹(shù),然后再進(jìn)行解析;
2.使用analyzer結(jié)合數(shù)據(jù)hive、源數(shù)據(jù)Metastore(新的catalog)進(jìn)行綁定,生成resolved LogicalPlan;
3.使用optimizer對(duì)resolved LogicalPlan進(jìn)行優(yōu)化,生成optimized LogicalPlan,優(yōu)化前使用了ExtractPythonUdfs(catalog.PreInsertionCasts(catalog.CreateTables(analyzed)))進(jìn)行預(yù)處理;
4.使用hivePlanner將LogicalPlan轉(zhuǎn)換成PhysicalPlan;
5.使用prepareForExecution()將PhysicalPlan轉(zhuǎn)換成可執(zhí)行物理計(jì)劃;
6.使用execute()執(zhí)行可執(zhí)行物理計(jì)劃;
7.執(zhí)行后,使用map(_.copy)將結(jié)果導(dǎo)入SchemaRDD。
到此這篇關(guān)于Spark SQL的整體實(shí)現(xiàn)邏輯的文章就介紹到這了,更多相關(guān)Spark SQL實(shí)現(xiàn)邏輯內(nèi)容請(qǐng)搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!
版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。