超大JSONファイルを解析します。

11734 ワード

超大JSONファイルを解析します。
1、需要
最近のプロジェクトでは50 G以上のJSONファイルをESに導入する必要があります。普通の行ごとにファイルを読み込み、JSONReaderストリームでファイルを読み込むのを試したことがあります。
2、解決策
解析するデータ構造は以下の通りです。
{"nameList":[{"name":"zhangsan"},{"name":"lisi"}],"ageList":[{"age1":"18"},{"age2":"12"}],"list":[{"a":"xxx","b":"zzz"}]}
構造は簡単ですが、json配列ごとに含まれているjsonオブジェクトが多すぎて、メモリが溢れてしまいます。
最終的にはJson Tokenのソリューションを採用しました。
	import org.codehaus.jackson.map.*;
    import org.codehaus.jackson.*;
    import java.io.File;
    public class ParseJsonSample {
      public static void main(String[] args) throws Exception {
        JsonFactory f = new MappingJsonFactory();
        JsonParser jp = f.createJsonParser(new File(args[0]));
        JsonToken current;
        current = jp.nextToken();
        if (current != JsonToken.START_OBJECT) {
          System.out.println("Error: root should be object: quiting.");
          return;
        }
        while (jp.nextToken() != JsonToken.END_OBJECT) {
          String fieldName = jp.getCurrentName();
          // move from field name to field value
          current = jp.nextToken();
          if (fieldName.equals("records")) {
            if (current == JsonToken.START_ARRAY) {
              // For each of the records in the array
              while (jp.nextToken() != JsonToken.END_ARRAY) {
                // read the record into a tree model,
                // this moves the parsing position to the end of it
                JsonNode node = jp.readValueAsTree();
                // And now we have random access to everything in the object
                System.out.println("field1: " + node.get("field1").getValueAsText());
                System.out.println("field2: " + node.get("field2").getValueAsText());
              }
            } else {
              System.out.println("Error: records should be an array: skipping.");
              jp.skipChildren();
            }
          } else {
            System.out.println("Unprocessed property: " + fieldName);
            jp.skipChildren();
          }
        }                
      }
    }
コードでは、ストリームとツリーモデル解析の組み合わせを使ってこのファイルを読みだします。個々の記録はツリー構造で読み取りますが、ファイルは常にメモリに読み込まれませんので、JVMメモリは爆発しません。最終的には、大きなファイルを読み込む問題が解決されました。