2016年6月21日 星期二

[Spark] 利用 Spark 將亂七八糟資料格式的 Fortigate Log 檔轉成關聯式資料

圖片來源:http://www.fastcompany.com/1842000/company-chaos-you-dont-know-youre-creating

不論資料多雜亂,在做資料分析之前,總是先要整理成關聯式資料,這一段一直是分析中最麻煩也最惱人的一段,特別是當資料量大的時候,其中可能問題又更多了.這次遇到的麻煩是要固定將機器每天的 Log 檔轉成關聯式資料,聽起來不難,是很常見的需求,但是看了資料格式之後整個傻眼.

這樣的格式麻煩點在:
  1. 非一般的資料格式: 既不是關聯式資料,也不是 Json 格式(真的很想打設計這種 log 出來的人),沒辦法輕易地整理.
  2. 分隔符號不固定: 雖然後面的資料是用 = 做為key和value分隔,但是前面四個欄位不是,表示資料要分開處理.
  3. 資料欄位內有空格: 如果預設用" "當做每個欄位的分隔符號,會在這些內部有空格的地方吃了大虧,所以要另外寫工具來區別這種情況.
  4. 每筆資料有的key不一致: 這是最麻煩的事.例如有些筆資料有 location 這個 key ,但是有些資料沒有...,連 null 都不給.所以就算你處理完上面三件事,每筆資料的欄位長度還是不一樣.

以下會逐步說明如何處理上述這幾個地方.
就處理資料邏輯來說,會先把資料根據欄位切開來,然後再把對應的直塞到欄位裡.但是這個資料因為每筆欄位不太一致,所以想說乾脆直接轉成 Json 來處理比較方便,因為我把所有東西都寫在同一航裡面,所以只好一起看這主要的部分:
用Spark 寫起來真的很簡單:
  • 第一行的 map 用了一個自已寫的_space_split 工具來避免上面提到的第三點--把值裡面的空白切開.  
  • 第二行把每一個 Row 切成前面四個和後面剩下的
  • 前面四個固定欄位直接人工塞 key 的名稱
  • 剩下的就用  分隔,轉成Python 中的 Dictionary 物件
  • encode 的用途在於原始資料預設 utf-8格式,在字串處理上會變成u'day',這樣的東西Spark 會沒辦法辨識成 Json 格式.
這一段完成之後已經將每個醜醜的 row 轉成 json 格式,至於每個 json 格式裡面的Key都不同沒有關係,交由 Spark 自己處理.因此我們透過 JsonRDD 讀取剛剛的檔案:
Spark 就會自動轉成DataFrame ,這時候可以用 printSchema() 和 show() 檢查一下欄位是不是正確,接著就可以用 write 快樂的轉成 parquet 存放了.