Dremel: 交互式分析Web數據

Dremel是一個可擴展的、交互式即時查詢系統,用於分析只讀的嵌套數據。Dremel能夠對集羣上的超大數據集進行交互式分析。Pig、Hive利用MapReduce執行查詢,須要在多個MR做業間傳遞數據,相比之下,Dremel是就地執行查詢的(MapReduce的瓶頸頗有可能就是在Map和Reduce之間傳遞數據)。Dremel並非用來取代MapReduce的,它能夠和MapReduce互相補充,好比用於分析MapReduce的輸出。算法

實現Dremel有2個問題:首先是通用的存儲層,好比GFS,一個高性能的存儲層對於就地查詢是很是關鍵的;其次是存儲格式,按列存儲對於扁平的關係數據很是合適,運用到嵌套數據更加困難,必需要保留結構信息,而且可以按任意域的子集重構記錄。編程

本文的主要內容就是如何按列存儲嵌套數據模型。數據結構

1.嵌套數據模型

編程語言使用的數據結構,分佈式系統交換的信息,結構化文檔,等等,能夠很天然地用嵌套結構表示。在Google,嵌套數據模型是大多數結構化數據處理的基礎。Dremel使用的嵌套數據模型可用下面語句表示:編程語言

τ是一個原子類型或者一個記錄類型。Dremel使用的原子類型包括整形、浮點數、字符串等;記錄包括一個或多個域,每一個域能夠是原子類型或其它記錄類型。Ai是記錄的第i個域,每一個域能夠選擇一個標籤,標籤*(repeated)表示重複域(可出現0或屢次),標籤?(optional)表示可選域(0或1次),無標籤(required)則表示必要域(只出現一次)。分佈式

上圖是論文裏給出的例子,定義了一個記錄類型Document表示網頁,以及該記錄的兩個實例。域DocId是必要域;Links是可選域,Links內能夠包含一系列的Backward和Forward,指向其它網頁的DocId;每一個文檔能夠有多個Name,表示能夠用不一樣的URL訪問該網頁;每一個Name能夠有多個Language(Code-Country對),以及可選域Url。r1和r2是知足該格式的兩個例子。 域的完整路徑使用’.’鏈接,好比Name.Language.Country。工具

整個數據模型能夠當作是一棵樹,只有葉子結點纔有值。性能

2.按列存儲

按列存儲有不少好處,好比更好壓縮率,減小查詢讀取的數據量。按列存儲關係數據很簡單,可是按列存儲嵌套數據很複雜,由於必須保存數據的結構信息。本小節解決記錄的按列無損存儲,快速編碼,高效記錄聚合等挑戰。大數據

2.1 重複級別和定義級別

數據自己不能告訴咱們記錄的結構。以Document的Name.Language.Code爲例,按列存儲後,連續兩個Code的值,咱們並不知道它們是屬於同一個Name下的兩個Language,仍是不一樣的兩個Name,以下圖三個Code的關係。所以爲了保存記錄的結構信息,Dremel引入了Repetition Level和Definition Level概念。ui

仍然以Code爲例,它在r1中出現了3次。’en-us’和’en’位於第一個Name,’en-gb’位於第三個Name。換句話說,’en’是在Language發生重複,’en-gb’是在Name發生重複。爲了區分這些狀況,Dremel爲每一個值分配一個重複級別。重複級別表明值是在哪一級發生重複。Name.Language.Code路徑上有兩個重複域,所以Code的重複級別能夠是0、一、2,0表示開始新記錄(或者理解爲在記錄一級重複)。根據定義,r1的三個Code的重複級別分別是0、二、1。注意r1的第二個Name裏沒有Code,爲了區分’en-gb’是第二個Name仍是第三個Name,必須’en’和’en-gb’之間插入NULL。編碼

在Code的例子裏,由於Code是Language的必要域,若是Code讀取了一個NULL,咱們就能夠肯定這個位置其實是一個沒有Language的Name。可是通常狀況下,還須要額外信息。以Country爲例,Country是Language的可選域,若是Country讀出一個NULL,那麼這個位置究竟是缺了Language的Name,仍是缺了Country的Language呢?

定義級別用於解決這個問題。定義級別表示這個值的完整路徑上有幾個域是能夠未定義(可選域或重複域)但卻已定義。對於非空的值,它的定義級別就等於完整路徑上可選域和重複域的數量;對於NULL,得看它出現的位置上實際定義了幾個可選域和重複域。以Country爲例,Name.Language.Country的可選域或重複域有三個,因此對於非空值,它的定義域必定是3;而對於NULL,則要看缺席的緣由,好比r1的第一個Name的第二個Language沒有Country,定義級別爲2,而第二個Name沒有Country,定義級別爲1。NULL告訴咱們此處本能夠有一個值,定義級別告訴咱們缺席的緣由。

r1和r2全部域的重複級別和定義級別以下圖所示。論文的附錄A提供了快速計算重複級別和定義級別的算法。

2.2 編碼

列的存儲都以block爲單位,值通過壓縮後,和對應的重複級別和定義級別一塊兒被編碼到block。好的編碼方式能夠儘量去掉沒必要要的數據。

性質一:特定的一列裏,非空值的定義級別都是相同的,而空值的定義級別確定小於非空值的定義級別。

性質二:重複級別老是小於定義級別。

利用性質一,咱們能夠不存儲非空值的定義級別和NULL值。根據性質二,定義級別爲0意味着重複級別也是0,所以DocId的兩個級別都不用存儲。

2.3 記錄的組裝

前面討論的是如何將記錄按列存儲,這一小節是如何將列重組爲記錄,這對面向記錄的處理工具(好比MapReduce)是很是關鍵的。給定域的一個子集,Dremel將只重組該記錄被選定的域。Dremel的思想是建立一個有限狀態機(FSM),負責讀取每一個域的值和級別。FSM的每一個狀態對應一個域,狀態的跳轉由重複級別決定:每讀取了一個值,Dremel查看下一個重複級別決定跳轉到哪一個狀態。

上圖顯示了重組完整記錄的有限狀態機。開始的狀態是DocId,每當讀取一個DocId,FSM跳轉到Links.Backward;根據重複級別的定義,1表示下一個Backward值屬於同一個Links,所以重複讀取,遇到0則表示Backward讀完了,跳轉到Links.Forward;Forward和Backward相似;跳轉到Code後,狀況更加複雜,由於Country和Code是兄弟,因此不論Code的重複級別爲什麼值,都跳轉到Country;當下一個Country的重複級別是2時,代表當前Language級別發生重複,跳轉到Code;不然Language級別無重複,跳轉到Name.Url;下一個Url的重複級別是1代表Name發生重複,跳轉到Code;不然Name結束,記錄讀取完畢。完整的算法在論文附錄B。

FSM的構造算法在論文附錄C,基本的思路比較簡單。假如現處於狀態f,即讀取域f的值,若是下一個重複級別是l,則回溯到級別爲l的祖先結點,而且選擇該祖先結點下的下一個(論文裏說的是first leaf,我的認爲有誤)葉子結點n爲跳轉狀態。所以咱們獲得了一個跳轉(f, l)->n。以Name.Language.Country爲例,假如讀取的下一個重複級別爲1,由於country的祖先中級別爲1的是Name,而Name在Language後的下一個葉子結點是Url,所以獲得跳轉(Name.Language.Country, 1)->Name.Url(而按照原文first leaf的解釋,跳轉的目標應該是Name.Language.Code,顯然是錯誤的)。

原文: Dremel: Interactive Analysis of Web-Scale Datasets. In VLDB'2010.

相關文章
相關標籤/搜索