轉(zhuǎn)載:https://www.codenong.com/jse7df02c3f366/
前言
數(shù)據(jù)字典 DataDictionary
數(shù)據(jù)血緣 DataLineage
元數(shù)據(jù)觸發(fā)器 MetaTrigger
一. 血緣分析的導(dǎo)推形式
sql
kafka streams
spark rdd
flink datastream
二. 血緣分析的技術(shù)方案分析。
通過調(diào)度器反向推導(dǎo)血緣關(guān)系早直。
通過計算引擎系統(tǒng)提供的血緣分析接口進行收集寥假。
通過計算引擎系統(tǒng)的解析過程源碼進行提取
通用的sql解析器工具
三. queryparser內(nèi)功心法.
語法解析過程
信息傳播過程
特定的計算模型
如何新增新的數(shù)據(jù)庫方言。
前言
最近在元數(shù)據(jù)的項目建設(shè)中霞扬,主要涉及了三方面的基礎(chǔ)工作分析糕韧。
數(shù)據(jù)字典 DataDictionary
數(shù)據(jù)字典算是元數(shù)據(jù)的最基礎(chǔ)功能枫振,相當(dāng)于元數(shù)據(jù)模型里面的實體∮┎剩可以進行信息的查詢及搜索粪滤,第三方API接口使用。
目前最核心的實體包括三塊:用戶(User)雀扶,數(shù)據(jù)集(Dataset)杖小,
數(shù)據(jù)管道(Datapipe)。
[用戶User實體] 可以通過ldap集成愚墓,可以用于關(guān)聯(lián)元數(shù)據(jù)實體及后期資產(chǎn)管理予权,甚至集成后期的數(shù)據(jù)安全建設(shè)。
[數(shù)據(jù)集Dataset實體] 則是不同數(shù)據(jù)源的模式浪册,可以額外包含很多細節(jié)的選項扫腺,包括樣例數(shù)據(jù),存儲開銷村象,健康度(字段描述完整性笆环,后期集成數(shù)據(jù)加載質(zhì)量檢測)。
[數(shù)據(jù)導(dǎo)管Datapipe實體] 數(shù)據(jù)導(dǎo)管主要關(guān)注數(shù)據(jù)流通過程煞肾,分為幾類咧织。最常用的是sql,其實可以是kafka streams, spark rdd之類的代碼籍救。這里的數(shù)據(jù)導(dǎo)管屬于靜態(tài)資源习绢。
數(shù)據(jù)血緣 DataLineage
前面定義了數(shù)據(jù)實體,接著就要定義數(shù)據(jù)關(guān)系蝙昙。
[User實體]關(guān)系由于重要度不太高闪萄,這里不做過多關(guān)注,留于后續(xù)考慮奇颠,甚至需要其它關(guān)系建立之后會有更多意義败去。
[Dataset實體]與[Datapipe實體]之間的關(guān)系主要由血緣分析這個過程完成。
我們定義這個數(shù)據(jù)關(guān)系為有向圖導(dǎo)管DagConduit烈拒。
如果大家熟悉haskell conduit庫的話圆裕,就會很自然想到conduit由pipe而來。
DagConduit由Datapipe 推導(dǎo)而來荆几,而Datapipe是依賴于Dataset吓妆。
這樣每個DagConduit形成了一個局部關(guān)系圖:
[Input Dataset] -> Datapipe -> [Output Dataset]
每個InputDataset又依賴于Datapipe,這樣每個DagConduit輸出自己的關(guān)系吨铸,在圖數(shù)據(jù)庫存儲里面進行關(guān)聯(lián)就會形成完整的dag關(guān)系圖了行拢。
這里的DagConduit就是我們今天的主角,下一節(jié)講會重點講解诞吱。
元數(shù)據(jù)觸發(fā)器 MetaTrigger
這里的主要意圖是完成元數(shù)據(jù)驅(qū)動編程的思想舟奠。
當(dāng)前主要考慮的點則是竭缝,通過血緣分析生成dag信息去觸發(fā)airflow調(diào)度器系統(tǒng)。
當(dāng)然元數(shù)據(jù)驅(qū)動的使用范圍非常廣泛沼瘫,也是非常核心的內(nèi)容抬纸。
后續(xù)會做更多的探索及進一步分享與交流。
一. 血緣分析的導(dǎo)推形式
血緣分析在這里主要是我們前文所說的DagConduit的推導(dǎo)過程晕鹊。這個推導(dǎo)過程很大依賴于Datapipe松却。
因為元數(shù)據(jù)是個通用平臺,可推導(dǎo)的范圍還是非常多的溅话,我們這里僅從實用角度考慮并介紹晓锻。
常見的etl過程主要分為sql, kafka streams, spark rdd, flink datastream,這幾個。
sql是最常用的Datapipe飞几,但是其變種也是最多的砚哆。
kafka streams, spark rdd, flink datastream則是另一種形式,會生成相應(yīng)的topology相關(guān)的lineage屑墨,由于靈活度不高躁锁,可以使用對應(yīng)的庫進行提取。
這里我們重點關(guān)注sql血緣分析卵史,因為sql這種dsl是最有表達力战转,最符合元數(shù)據(jù)模型的。
甚至kafka, spark, flink也絕大多數(shù)會提供sql接口以躯。
由于本人大多時間關(guān)注于sql推導(dǎo)模型槐秧,未對其它模型做過多探索,將于后續(xù)交流及使用后補充相關(guān)內(nèi)容忧设。
二. 血緣分析的技術(shù)方案分析刁标。
我們常見的血緣分析實現(xiàn)方式主要分為四種:
通過調(diào)度器反向推導(dǎo)血緣關(guān)系。
因為調(diào)度器跟DagConduit有著很密切的關(guān)系址晕。我們很容易從調(diào)度器的每個DAG里面提取出對應(yīng)的Datapipe以及它們的關(guān)系膀懈。
這種方案的可行性非常高,成本非常廉谨垃。但缺點也是很顯而易見的启搂,這種方案不能支持字段級別的血緣,而字段關(guān)系對于元數(shù)據(jù)非常重要刘陶,甚至是后續(xù)擴展數(shù)據(jù)質(zhì)量及數(shù)據(jù)安全的重要思路之一狐血。并且對于業(yè)務(wù)方面的影響分析也是非常有價值意義的。
通過計算引擎系統(tǒng)提供的血緣分析接口進行收集易核。
由于數(shù)據(jù)治理的重要性逐漸為人所認(rèn)識,血緣分析功能也成為了etl工具箱的重要一環(huán)浪默。所以hive就直接提供了血緣分析接口牡直。
這種方式的優(yōu)點是顯而易成的缀匕,即支持了字段級別血緣分析,成本也是非常低的碰逸,對于大部分公司其實是夠用的乡小。但是缺點也是非常明顯的。
因為計算引擎與血緣分析在一起饵史,如果血緣分析的功能需要增加满钟,計算引擎勢必也要受到牽連。畢竟字段血緣分析在很多情況下胳喷,很多場景下并不是標(biāo)準(zhǔn)統(tǒng)一的湃番。比如select a from t where b = 'c'。這里的a字段到底需不需要依賴于b的值呢吭露?這里不同的需求可能找到的答案并不會一致吠撮。如果需要更一步進行統(tǒng)計信息獲取后進行相關(guān)的血緣擴展分析,也是非常困難的讲竿,因為接口是非常固定有限的泥兰。
另外血緣分析在運行時執(zhí)行,這樣血緣分析已經(jīng)與系統(tǒng)運行時有了直接的綁定關(guān)系题禀。所以無法進行血緣分析驅(qū)動鞋诗,將一個系統(tǒng)換成另一個系統(tǒng)。如果是sql解析出來的血緣分析迈嘹,我們可以通過元數(shù)據(jù)觸發(fā)器觸發(fā)到各種各樣的平臺削彬,是非常靈活的。
當(dāng)然江锨,這些弱點對于實際使用來說并不是特別致命吃警。畢竟成本低,且簡單可用是非常有吸引力的啄育,系統(tǒng)耦合之類的事情雖然比較爛酌心,但先用起來再說,無可厚非挑豌,所以atlas也是這么干的安券。所以我堅信atlas可以解決問題,但絕不是未來氓英。并且這里面還隱藏著另一個大的隱患侯勉,并不是所有etl工具箱都會給你提供血緣接口,原因很明顯铝阐。對于成熟的產(chǎn)品址貌,絕不會讓血緣分析時與計算引擎綁定在一起受波折。
所以,sql血緣解析才是未來练对。
通過計算引擎系統(tǒng)的解析過程源碼進行提取
這個應(yīng)該是最常用的做法了遍蟋,成本雖然高一點,但是整體可控螟凭,畢竟基礎(chǔ)代碼完成了很大一部分功能了虚青,還可以按需定制,對于個人成長及公司的定制化需求都是非常令人滿意的螺男。畢竟互聯(lián)網(wǎng)公司大部分使用開源產(chǎn)品棒厘,開源的世界任你折騰。
這里面困惑其實也不少下隧。如果是商業(yè)產(chǎn)品奢人,如果商家沒有提供解析器,基本上就非常無奈了汪拥。對于每套計算引擎各自的規(guī)則可能不一樣达传,致使門檻非常高了,甚至出現(xiàn)了專用的商業(yè)公司去統(tǒng)一解決這個問題迫筑。甚至對于字段級血緣提取宪赶,代碼的功力也是非常有要求的。并且開源軟件為了自己的一些內(nèi)部功能脯燃,在代碼里面滲雜了過多的東西搂妻,致使學(xué)習(xí)成本可以嚇退不少人了。
通用的sql解析器工具
由于前面的問題辕棚,所以大家都想要一套通用的sql解析工具去專門解決sql分析的問題欲主。但是這個里面涉及一個非常嚴(yán)重的問題,就是成熟度逝嚎。由于sql解析過程有非常大的工作量扁瓢,需要對語法規(guī)則非常熟練,寫起來繁雜的工作量及系統(tǒng)多樣性很容易讓人退縮补君。所以市面上一直找不到成熟的通用的sql解析器引几。
所以這里面就回歸到了我們的主角,queryparser由此而生挽铁。queryparser是uber公司開發(fā)的伟桅,成熟的多年應(yīng)用到了生產(chǎn)系統(tǒng)。目前支持hive, queryparser, vertica, teradata叽掘。對于pg系統(tǒng)楣铁,有由專用的gpu數(shù)據(jù)庫公司SQream員工開發(fā)的解析器hssqlppp。這兩套系統(tǒng)采用通用的解析器內(nèi)核parsec更扁。
那么在這里放出地址給各位:
hive解析器
https://github.com/uber/queryparser/tree/master/dialects/hive
presto解析器
https://github.com/uber/queryparser/tree/master/dialects/presto
vertica解析器
https://github.com/uber/queryparser/tree/master/dialects/vertica
teradata解析器
https://github.com/LeapYear/queryparser/tree/leapyear-master/dialects/teradata
pg解析器
https://github.com/JakeWheat/hssqlppp
這個queryparser強大在哪里呢盖腕?
一看嚇?biāo)廊撕斩诵拇a只要7000多行。而sql結(jié)構(gòu)定義就占了3000多行赊堪,也就是說邏輯只有4000行左右面殖,擅抖吧,奧利給!
三. queryparser內(nèi)功心法.
平復(fù)一下內(nèi)心的平靜哭廉,讓我們來了解一上queryparser到底是怎么實現(xiàn)的。
queryparser包含了核心邏輯的實現(xiàn)(大部分就是標(biāo)準(zhǔn)sql邏輯)相叁,每個方言有各自特寫的擴展遵绰,我們這里以queryparser-hive為例。
queryparser-hive將一些特定sql的功能處理掉增淹,核心功能交給 queryparser來處理椿访。由于我們接觸的大部分是標(biāo)準(zhǔn)sql,我們在這里分析標(biāo)準(zhǔn)的sql語句虑润,在后續(xù)源碼篇里面我們會進一步介紹詳細介紹queryparser-hive與queryparser的整體過程成玫。
整個解析過程分為三個步驟:
parseManyAll 語法解析過程
將文本打碎(詞法分析)并組裝成結(jié)構(gòu)化(語法分析)
resolveHiveStatement 信息傳播過程
遍歷數(shù)據(jù)結(jié)構(gòu),進行外部的catalog關(guān)聯(lián)拳喻,以及相應(yīng)信息的傳遞,屬于通用的信息加工邏輯階段哭当。
getColumnLineage 特定的計算模型
計算模型分為很多種,有各自的需求定義冗澈。在提供的接口中钦勘,用戶實現(xiàn)特定的邏輯完成所需的功能。
queryparser提供了兩種模型亚亲,一種是字段血緣模型彻采,一種是數(shù)據(jù)計算模型。當(dāng)然我們可以隨意實現(xiàn)接口定制自己的模型捌归。
比如通過實現(xiàn)不同的sql邏輯處理方法將sql語句轉(zhuǎn)換成對應(yīng)的http restful請求肛响。
一個類似的功能可參照:
1
2
SELECT status, content_type, content::json->>'data' AS data
FROM http_patch('http://httpbin.org/patch', '{"this":"that"}', 'application/json');
https://github.com/pramsey/pgsql-http
1. 語法解析過程
語法解析常用的實現(xiàn)分為兩種:
一種是parser generator,就是你寫好規(guī)則惜索,自動幫你生成解析代碼特笋,比如常見的antlr就是。這種方式的特寫是性能高门扇,效率高雹有。缺點則是定制化擴展弱,異常信息非常難讀懂臼寄。
另一種是parser combinator霸奕,這種就是你自己手寫語法規(guī)則,非常靈活吉拳,效率會低一點质帅,可控性比較強。
queryparser就是使用了parser combinator方式進行解析,所以我們可以自由定制煤惩。
語法解析的目地是生成AST嫉嘀,簡單來說就是一個遞歸的數(shù)據(jù)結(jié)構(gòu),有點類似json魄揉。在語法解析過程中要做的工作就是剪侮,定義數(shù)據(jù)結(jié)構(gòu),然后把信息塞進去洛退。其實難度并不大瓣俯,但是由于sql規(guī)則的復(fù)雜度,整個工作量并不輕松兵怯。
語法規(guī)則的過程分為兩部分:詞法解析及語法解析彩匕。
為什么需要詞法解析呢?因為sql跟平常我們所說的csv文件并不一樣媒区,支持可以使用分隔符來定義結(jié)構(gòu)驼仪。有些東西在不同的環(huán)境下有不同的意義。比如任何事物在注釋里面它就沒有效果了袜漩,里面可能還有變量聲明绪爸,關(guān)鍵字信息等。
所以詞法分析器就是按sql的基本單元進行拆分噪服,然后語法分析器將其組裝起來形成遞歸的結(jié)構(gòu)體毡泻。為了便于理解,我們給出實際代碼里面的詞法結(jié)構(gòu)及邏輯片段粘优。
https://github.com/uber/queryparser/blob/master/dialects/hive/src/Database/Sql/Hive/Token.hs
可以看出仇味,hive的基本單元分為了TokWord(通用名稱), TokString(字符), TokNumber(數(shù)字), TokSymbol(符號), TokVariable(變量)
這個解析的過程叫做scanner,就是常用的字符處理生成Token流雹顺。
https://github.com/uber/queryparser/blob/master/dialects/hive/src/Database/Sql/Hive/Scanner.hs
有了Token流丹墨,我們進行組合生成AST。
那么我們可以看HIVE AST的結(jié)構(gòu)定義:
https://github.com/uber/queryparser/blob/master/dialects/hive/src/Database/Sql/Hive/Type.h?
然后hive的HiveStandardSqlStatement包包含的Statement定義在queryparser核心結(jié)構(gòu)里面嬉愧,由于sql結(jié)構(gòu)定義query部分比較多贩挣,單獨拎出來形成了兩個文件:
https://github.com/uber/queryparser/blob/master/src/Database/Sql/Type.hs
接下來就是把token組裝起來。
由于每個方言組裝邏輯語法規(guī)則不一樣没酣,所以各自有自己的實現(xiàn)王财,核心接口并未提供。
https://github.com/uber/queryparser/blob/master/dialects/hive/src/Database/Sql/Hive/Parser.hs
解析過程并不復(fù)雜裕便,就是按結(jié)構(gòu)體深度遞歸绒净,跟json解析差不了多少。
整個過程就是偿衰,至上而下解析挂疆,解析一項改览,如果失敗了則嘗試其它項,深度遞歸下去缤言。
體力活比較重宝当,因為規(guī)則多,每一項都要寫規(guī)則嘗試匹配胆萧。
就這樣庆揩,整個結(jié)構(gòu)體就組裝起來了。
2. 信息傳播過程
其實queryparser的信息傳播過程非常簡單跌穗,就是單純從catalog里面去查詢表信息盾鳞,關(guān)聯(lián)到表生成的字段,然后將以前的表名轉(zhuǎn)換成表信息瞻离,生成引用信息。
https://github.com/uber/queryparser/blob/master/src/Database/Sql/Type/Scope.hs
具體內(nèi)容我們可以看前后結(jié)果對比
可以看到乒裆,sql解析之前表名套利,列名信息就是簡單的字符OQTableName, UQColumnName。
解析之后就映射成了實際的各種形式鹤耍。resolve出的RTableName就包含了從catalog里面查詢出來的表的所有列員肉迫。
這個信息可以用來解析insert into時不帶字段名,以及select *時的一些模糊邏輯稿黄。
當(dāng)然本人覺得如果sql夠標(biāo)準(zhǔn)的話喊衫,表的字段信息是完成可以從傳播過程中自動推導(dǎo)的,而不用依賴于外部提供的catalog模式信息杆怕,這個也是本人正在嘗試加強信息傳播過程中優(yōu)化的方向之一族购。
整個resolve過程代碼:
https://github.com/uber/queryparser/blob/master/src/Database/Sql/Util/Scope.hs
由于是概述篇,就不展開講述陵珍,后續(xù)將在源碼篇里詳細介紹寝杖。
3. 特定的計算模型
有了前面兩部分過程之后,我們的結(jié)構(gòu)體經(jīng)過遍歷關(guān)聯(lián)處理有了更詳細的信息互纯。
最后一步則是通過這個結(jié)構(gòu)體去做對應(yīng)的計算瑟幕。
因為整個遍歷過程跟處理過程,相似度比較高留潦。
所以queryparser提供了一個標(biāo)準(zhǔn)計算模型只盹,應(yīng)用則可以定制化特定部分進行邏輯處理, 只需要編寫對應(yīng)的函數(shù)兔院,不需要自己去編寫整個過程殖卑。
當(dāng)然如果你有興趣,自己定義重寫或者擴展一套計算模型也是非常方便的秆乳。
我們可以看一下這個計算邏輯的定義:
queryparser定義了兩種計算模型:
數(shù)據(jù)計算模型
也就是說可以真實通過在數(shù)據(jù)上運行sql上跑出結(jié)果懦鼠。當(dāng)然這個里面的邏輯并不是非常優(yōu)化的钻哩,沒有做rbo或者cbo相關(guān)的優(yōu)化,并且邏輯實現(xiàn)比較簡單肛冶。所以不適合海量數(shù)據(jù)運算街氢,則提供基礎(chǔ)實現(xiàn)版本。
https://github.com/uber/queryparser/blob/master/src/Database/Sql/Util/Eval/Concrete.hs
這里面的細節(jié)由于跟本文關(guān)聯(lián)不大睦袖,就不一一介紹了珊肃,如有興趣,可以源碼篇作更進一步介紹馅笙。
字段血緣分析模型
https://github.com/uber/queryparser/tree/master/src/Database/Sql/Util/Lineage
字段血緣模型就是用得比較多的了伦乔,簡單來講呢,依舊是深度遍歷到列級別董习,然后組裝起來烈和。
我們可以簡單看看計算模型的組裝過程分為哪些。
https://github.com/uber/queryparser/blob/master/src/Database/Sql/Util/Eval.hs
最基礎(chǔ)的內(nèi)容是常量與(列)表達式皿淋,表結(jié)構(gòu)
表結(jié)構(gòu)向上傳播到TablishJoin , TablishLateralView , SelectFrom
列表達式通過表達式一層層往上計算招刹。
然后到達SelectWhere, JoinCondition, SelectTimeseries , SelectGroup, SelectHaving
然后組合形成了基本的select語句
然后加上CTE功能就形成了完整的Query,然后在SelectFrom里面可以遞歸到這個Query進行遞歸組合窝趣。
當(dāng)然這個過程我們會在源碼篇詳細講解疯暑,對于普通讀者,可以了解一下大致的計算過程哑舒。
整個過程有個EvalContext妇拯,
evalAliasMap里面會記錄表別名對應(yīng)的信息,
evalFromTable里面會記錄表對應(yīng)的信息洗鸵,
evalRow里面會對應(yīng)字段對應(yīng)的信息
最終解析出來的結(jié)果有兩種形式:
對于每個表FQTN越锈, 有對應(yīng)的ColumnPlusSet(表依賴集及字段依賴集)
對于表的每個字段FQCN,有對應(yīng)的ColumnPlusSet(表依賴集及字段依賴集)
有人可能奇怪了预麸,在什么時候瞪浸,字段會依賴于表?
這個在select count(1) as cnt from b的時候cnt就是依賴于表的吏祸。當(dāng)然其它情況对蒲,我會進一步整理后補充。
4. 如何新增新的數(shù)據(jù)庫方言贡翘。
我們前面講過桦他,整個血緣分析分為三部分梨与。
第一部分sql解析的這個詞法解析及語法解析比較依賴于sql的語法規(guī)則乘陪,所以需要手寫术瓮,難度并不大,只是工作量比較大踊东。比如支持存儲過程之類的也是語法規(guī)則問題北滥。
第二部分信息傳播刚操,基本上是通用的。對于除標(biāo)準(zhǔn)sql以外的信息再芋,我們大部分不需要處理菊霜,特定的需要處理的工作量也非常少,可以簡單抄抄改改济赎。比如支持存儲過程之類的大部分也是sql邏輯處理后組合起來鉴逞。
第三部分計算模型,也基本上是通用的司训,由于對于血緣分析來說构捡,所涉及到關(guān)注面會更少,所需要改動是最小的壳猜。勾徽。。
5. SQL解析潮流從此開始
所以我們可以看到统扳,queryparser僅僅就干好了一件事情捂蕴,就幾千行代碼,并且干得簡單闪幽。擴展性也很強。
當(dāng)然我們也注意到了涡匀,它的整個列信息推理過程比較原始盯腌,直接查詢了catalog,但是也是非常方便后續(xù)擴展的陨瘩。
它的計算模型對比其它解析器是非常大的一個亮點腕够,你可以基于各種方言寫支持各種生態(tài)的擴展。只需要將對應(yīng)方言規(guī)則的sql解析后舌劳,實現(xiàn)對應(yīng)計算模型里的方法即可帚湘,給了我們相當(dāng)大的想象力。
你可以配置sql去做http restful遞歸請求甚淡,配置sql去做etl數(shù)據(jù)加載大诸。。贯卦。