2015年8月1日 星期六

使用 jq、awk、sort、uniq、tail、diff、comm 處理 JSON 大檔

跟朋友相約參加了黑客松,主要是分析 SPAM 資訊,由於官方提供的是一個很大檔案的 json format,大多操作都適用 jq 指令處理,盡量不寫 code 來分析 XD

首先,只對指定欄位取出資料:

$ cat data_set.input
[
   { "field1":"1" , "field2": "2", "field3": 3, "field4" : [1, 2, 3] } ,
   { "field1":"a" , "field2": "b", "field3": 4, "field4" : [1, 2] } ,
   ...
}


$ < data_set.file jq '.[] | .field1 +"-" + .field2 '
"1-2"
"a-b"
...


有時會碰到資料欄位是 number ,這時會出現 string and number cannot be added 的部分,可以這樣做:

$ < data_set.input jq '.[] | .field1 +"-" + (.field3 | tostring) '
"1-3"
"a-4"
...


有時想看某個欄位個數:

$ < data_set.input jq '.[] | .field1 +"-" + (.field4 | length | tostring) '
"1-3"
"a-2"
...


接著偷懶用 awk 整理資料:

$ < data_set.file jq '.[] | .field1 +"-" + .field2 ' | awk -F'"' '{print $2}'
1-2
a-b
...


有時需要判斷數值大小後,來決定是否輸出:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}'

輸出後,可以透過 sort 跟 uniq 整理一下:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq

有時搭配 uniq -c 計算屬性後,再用 sort -n 來排序:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq -c | sort -n

這時,輸出的結果就有指定屬性從小排到大的特性,如果第 1234 個 line 開始是你要的資料,可以搭配 tail 指令取出:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq -c | sort -n | tail -n +1234

甚至,取出後再搭配 awk 把前置數字去除,只要重要結果即可:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq -c | sort -n | tail -n +1234 | awk -F ' ' '{print $2}'

最後,如果有 lookup_pattern 跟 check_data 想要比對,記得都要把兩者做 sort,就可以用 diff 跟 comm 兩個指令:

$ sort lookup_pattern > lookup_pattern.sorted
$ sort check_data > check_data.sorted


這時想要檢查沒有落在 lookup_pattern.sorted 的清單或個數:

$ diff lookup_pattern.sorted check_data.sorted | grep "<"
$ diff lookup_pattern.sorted check_data.sorted | grep -c "<"


那如果想看有 match 到的清單:

$ comm -1 -2 lookup_pattern.sorted check_data.sorted

如此一來就類似作為清單比對的動作。若比較的條件太多時,只好寫寫 python 啦:

#!/usr/bin/python
#
# input.log、p1.log、p2.log 都是以 line 為單位的資料
#

in_data = open('input.log').read().split("\n")

pattern_data1 = open('p1.log').read().split("\n")
pattern_data2 = open('p2.log').read().split("\n")

lookup1 = {}
for i in pattern_data1:
        lookup1[i] = ''

lookup2 = {}
for i in pattern_data2:
        lookup2[i] = ''

for i in in_data:
    if i in lookup1:
         print " data in lookup1"
    elif i in lookup2:
         print " data in lookup2 && not in lookup1"

沒有留言:

張貼留言