iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

0
Elastic Stack on Cloud

Elastic 30天自我修行系列 第 31

使用 jq 將既有JSON大型檔案轉成ND JSON

講一下使用情境,如果手邊有一個2GB的JSON檔案,而且JSON檔中有巢狀資料,那勢必要透過 Linux 的命令列直接進行處理才是最快的手法。如果不事先進行預處理,無法上傳到 ElasticSearch。

之前有提過在 R 中的 jsonlite 套件,只能針對結構式資料 data.frame 進行 ND JSON 格式的輸出,面對不結構化的巢狀資料就無法處理。

今天的目標很簡單,就是把以下的JSON檔案 (第1筆資料有3個欄位,但第2筆資料只有1個欄位)

{"id1":{"id":["a0001"],"price":["99"],"made":["Taiwan"]},"id2":{"id":["a0002"]}} 

直接透過 linux 的 jq 工具轉換成

{ "index": { "_index" : "test4" } }
{"id":["a0001"],"price":["99"],"made":["Taiwan"]}
{ "index": { "_index" : "test4" } }
{"id":["a0002"]}

因為我們的目標是利用JSON檔案進行分析,並不是成為 jq 大神,所以直接將試出來的解法公布

cat dirty_data1.json | jq   -c '.[]' | jq -r ' . | tostring | "{ \"index\": { \"_index\" : \"test4\" } }\n"   + .'  > clean_nd.json

第1段的 cat 指令:將 json 檔案送往到 jq
第2段的 jq 指令:遇到最外層的[] 後將資料進行處理,讓每筆紀錄加上斷行符號

{"id":["a0001"],"price":["99"],"made":["Taiwan"]}
{"id":["a0002"]}

第3段的 jq 指令:在每一行前面再加上 { "index": { "_index" : "test4" } } 字串。
其中的 -r 參數是指定字串的輸出格式為raw strings,所以你可以使用 \ 跳脫符合的語法去輸出雙引號與斷行。

先看個簡單版本的,就能讓剛剛看起來很長的指令,變得簡單些。
把 "." 小數點符號,想成是每一筆紀錄;tosting 是固定語法,是為了後續進行字串連結。

cat dirty_data1.json | jq   -c '.[]' | jq -r ' . | tostring | "我要加上的字串\n"   + .' 

效果是

我要加上的字串
{"id":["a0001"],"price":["99"],"made":["Taiwan"]}
我要加上的字串
{"id":["a0002"]}

最後再輸出到 > 另一個新檔就完成了。


然後有時,你拿到的 JSON 檔案可能是最外面再加上一組 []符號的JSON 檔案

[{"id1":{"id":["a0001"],"price":["99"],"made":["Taiwan"]},"id2":{"id":["a0002"]}} ] 

這時候只要把指令改成

cat dirty_data.json | jq   -c '.[][]' | jq -r ' . |  tostring | "{ \"index\": { \"_index\" : \"test4\" } }\n"   + .' > clean_nd.json

差異只在第一個例子中的第2組操作由

jq   -c '.[]' 

變成了

jq   -c '.[][]' 

就這樣簡單就快速可以搞定了!

實務上,在處理大型文件時,linux命令列下的各種工具 awk sed ag jq 還是有其處理速度上的優勢。所以有時候還是得要把這些處理手法給當成筆記抄錄下來。

當然,如果是新的 JSON 資料,平時就透過 API 往 ElasticSearch 丟,就不存在今天介紹範例的使用情境囉。


上一篇
學習 ElasticSearch 的第三十天心得
系列文
Elastic 30天自我修行31

尚未有邦友留言

立即登入留言