天天看點

基于檔案的多表join實作參考

  用例:有N個檔案,每個檔案隻有一列主鍵,每個檔案代表一種屬性。即當如PRI1主鍵在A檔案中,說明PRI1具有A屬性。這種場景,一般用于資料的篩選,比如需要既有屬性A又有屬性B的主鍵有哪些?就是這類場景。

  如何處理該場景?

  如果抛卻如題所說檔案限制,那我們如何解決?

  比如,我們可以将每個檔案資料導入到redis中,資料結構為hash, redis-key為pri主鍵,hash-key為屬性X, hash-value為1或不存在。在做判定的時候,隻需找到對應的key, 再去判斷其是否具有對應屬性即可解決問題了。

  這個方案看起來比較合适,但有兩個缺點:1. redis記憶體資料庫,容量有限,不一定能滿足大資料量的場景; 2. 針對反向查詢的需求無法滿足,即想要查找既含有A屬性又含有B屬性的主鍵清單,就很難辦到。

  再比如,我們可以使用類似于mysql之類的關系型資料,先将單檔案資料導緻單表中,表名以相應屬性辨別命名,然後以sql形式進行臨時計算即可。sql參考如下:

  應該說這種解決方案算是比較好的了,在計算不大的情況下,這種複雜度在資料庫領域簡直是小場面了。需要再次說明的是,在資料庫會建立一個個的小表,它隻有一列主鍵資料,然後在查詢的時候再進行計算。這種方案的問題在于,當辨別越來越多之後,就會導緻小表會越來越多,甚至可能超出資料庫限制。原本是一個一般的需求,卻要要求非常好資料庫支援,也不太好嘛。

  不過,上面這個問題,也可以解決。比如我們可以使用行轉列的形式,将以上小表轉換成一張大表,随後将小表删除,進而達到資料庫的普通要求。合并語句也不複雜。參考如下:

  如此,基本完美了。

  如果我沒有外部存儲媒體,那當如何?如題,直接基于檔案,将多個合并起來。看起來并非難事。

  如果不考慮記憶體問題,則可以将每個檔案讀入為list, 轉換為map存儲,和上面的redis實作方案類似。隻是可能不太現實,也比較簡單,忽略實作。

  再簡單化,如果我們每個檔案中儲存的主鍵都是有序的,要想合并就更簡單了。

  基本思路是,兩兩檔案合并,依次讀取行,然後比對是否有相等的值,然後寫到新檔案中即可。

  另外,如果要做并行計算,可以考慮使用上一篇文章提到的 fork/join 架構,非常合場景呢。

  主要算法為依次周遊各檔案,進行資料判定,然後寫目标檔案。具體實作如下:

  總體算法架構就是這樣了,外部調用時,可以串行計算調用 joinById, 自行合并。也可以直接joinMultiFile, 内部進行并行計算了。然後,最後再可以按照自行要求,做順序固化。此處并行計算的方案,正則上篇中講到的fork/join.

  如上計算過程中,需要使用一些輔助型資料結構,以表達清楚過程。以下為輔助類資訊:

  還是很簡單的吧。

  沒有測試不算完成,一個好的測試應該包含所有可能的計算情況,結果。比如幾個檔案合并,合并後有幾行,哪幾行的資料應該如何等等。害,那些留給使用者自行完善吧。簡單測試如下。

  下面這個并行計算沒有斷言,一是懶得加,二是這種确實也複雜,這也是和分布系統排查問題難表暗合之意。另外值得一提的是,為了驗證代碼的穩定性,單測中添加了一個檔案的随機打亂,進而保證了任意順序都可拿到最終結果。而在實際應用中,可以按照檔案行數大小排序,使用小檔案與小檔案合,大檔案與大檔案合,進而避免許多空行讀而浪費性能。這也是自己實作的好處,想起來哪裡想調整下,立即橫刀立馬。

下面給幾個樣例檔案:

  以上工具類,可以看作是對前面所示sql語義的同等實作,雖不能與官方同日而語,但也有一定的應用場景,隻待各位發現。供諸君參考。(誰知道呢,也許你用MR更簡單更高效)

不要害怕今日的苦,你要相信明天,更苦!

繼續閱讀