簡體   English   中英

如何使用Java中的Streaming API解析JSON日志文件,然后輸出列表日志文件

[英]How to parse JSON log file with Streaming API in Java, then output tabulated log file

我有一個問題,我試圖解析以JSON格式存儲的大型日志文件,然后將數據列表並輸出為另一個JSON文件。 以下是我正在解析的日志文件的格式:

{
"timestamp": "2012-10-01TO1:00:00.000",
"id": "someone@somewhere.net",
"action": "Some_Action"
"responsecode": "1000"
}

此處的操作是某些用戶執行的操作,響應代碼是該操作的結果。

時間戳和id實際上與我的制表無關,我只對動作/代碼字段感興趣。 在任何給定的日志文件中可能有數萬個這樣的條目,我想要做的是跟蹤所有類型的操作響應代碼及其各自的出現次數。

下面是我想要生成的輸出的示例。

{"actionName": "Some_User_Action",
"responses": [{"code": "1000", "count": "36"},
              {"code": "1001", "count": "6"},
              {"code": "1002", "count": "3"},
              {"code": "1003", "count": "36"},
              {"code": "1004", "count": "2"}],
"totalActionCount": "83"}

所以基本上,對於每個Action,我想跟蹤它生成的所有不同響應以及每個響應發生的次數。 最后,我想跟蹤該行動的總回復總數。

目前,我已經為輸出對象創建了一個Java類,我計划在其中存儲輸出數據。 我也對我應該存儲響應數組的格式和它們各自的計數數字有點困惑。 響應代碼類型的總數也因Action而異。

根據我的研究,我似乎需要使用Streaming API來使用JSON解析。 使用Streaming API的原因主要是由於使用非流API需要的內存開銷量,這可能與這些日志文件的大小無法實現。 我目前正在考慮使用Jackson或GSON,但我無法找到任何具體的示例或教程來幫助我入門。 有誰知道一個很好的例子,我可以學習或有任何關於如何解決這個問題的提示? 謝謝!

編輯:我的班級定義。

public class Action {



public static class Response {

    private int _resultCode;
    private int _count = 0;

    public Response() {}

    public int getResultCode() { return _resultCode; }
    public int getCount() { return _count; }

    public void setResultCode(int rc) { _resultCode = rc; }
    public void setCount(int c) { _count = c; }

}

private List<Response> responses = new ArrayList<Response>();
private String _name;

// I've left out the getters/setters and helper functions that I will add in after.

}

如果我正在使用Jackson,並希望最終能夠輕松地將此對象序列化回JSON,那么我是否有關於如何定義此類的建議? 目前我在main()方法中使用以下方法創建此Action類型的另一個ArrayList:List actions = new ArrayList(); 使用HashMaps或其他替代品是更好的選擇嗎? 此外,它是否允許我使用傑克遜輕松將其序列化為JSON?

好的,首先,傑克遜可以將數據綁定與流媒體相結合。 您只需要一個JsonParser (使用JsonFactory創建,其實例可以從ObjectMapper ,或直接構造)。 然后,您可以將流提前到第一個條目,並從那里開始使用數據綁定( ObjectMapper.readValue(...) )。 這只會讀取獲取所需單個值實例所需的最小值。

甚至更好,一旦到達陣列,使用“readValues()”方法

ObjectMapper mapper = new ObjectMapper();
JsonParser jp = mapper.getJsonFactory().createJsonParser(sourceFile);
while (jp.nextToken() != JsonToken.START_ARRAY) { }
MappingIterator<Response> it = mapper.readValues(jp, Entry.class);
while (it.hasNextValue()) {
   Response value = it.nextValue();
   // process it; keep count, whatever
}

要輸出,您可能需要考慮Jackson CSV模塊 :它可以使用CSV變體之一來寫入條目; 你可以將分隔符重新定義為你喜歡的任何東西。 有關示例,請參閱項目自述文件

您可以查看Genson庫http://code.google.com/p/genson/ ,在Wiki頁面上,您將找到有關如何使用它的一些示例。 自首次發布以來,它提供了流媒體模型,並且似乎是傑克遜之后最快的,見基准

如果你想做一些真正有效的事情並且內存占用量很小,可以通過實例化JsonReader直接使用流式api,然后使用它來讀取記錄的結構並增加你的計數器。

否則你可以使用Genson實例直接將文件解析為java對象,但在你的情況下我不認為它是正確的解決方案,因為它需要你將所有對象存儲在內存中!

以下是直接使用流式api的快速示例。 它不會精確打印您期望的結構,因為它需要更多代碼來有效地計算您的結構:

public static void main(String[] args) throws IOException, TransformationException {
    Map<String, Map<String, Integer>> actions = new HashMap<String, Map<String, Integer>>();
    Genson genson = new Genson();

    ObjectReader reader = genson.createReader(new FileReader("path/to/the/file"));
    while(reader.hasNext()) {
        reader.next();
        reader.beginObject();
        String action = readUntil("action", reader);
        // assuming the next name/value pair is responsecode
        reader.next();
        String responseCode = reader.valueAsString();
        Map<String, Integer> countMap = actions.get(action);
        if (countMap == null) {
            countMap = new HashMap<String, Integer>();
            actions.put(action, countMap);
        }

        Integer count = countMap.get(responseCode);
        if (count == null) {
            count = 0;
        }
        count++;
        countMap.put(responseCode, count);

        reader.endObject();
    }

    // for example if you had 2 different response codes for same action it will print
    // {"Some_Action":{"1001":1,"1000":1}}
    String json = genson.serialize(actions);
}

static String readUntil(String name, ObjectReader reader) throws IOException {
    while(reader.hasNext()) {
        reader.next();
        if (name.equals(reader.name())) {
            return reader.valueAsString();
        }
    }
    throw new IllegalStateException();
}

您可以逐個解析您的記錄,因此我不認為JSON結構的內存消耗超過幾千字節。 只是創造

class Something {
    String action;
    int responsecode;
    // do not include the fields you don't need
}

並在每一步中讀取一條記錄。 Guava的HashMultiset<String, Integer>及其方法putcountsize為您提供所需的一切。 如果你的內存耗盡(因為巨大的Multimap),你可能需要一個數據庫,但我先嘗試一下這個簡單的解決方案。

對於輸出JSON,您可能需要GSON的TypeAdapterJsonSerializer 或者作為黑客,您可以輕松地手動生成輸出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM