超大JSONファイルを解析します。
11734 ワード
超大JSONファイルを解析します。
1、需要
最近のプロジェクトでは50 G以上のJSONファイルをESに導入する必要があります。普通の行ごとにファイルを読み込み、JSONReaderストリームでファイルを読み込むのを試したことがあります。
2、解決策
解析するデータ構造は以下の通りです。
最終的にはJson Tokenのソリューションを採用しました。
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メモリは爆発しません。最終的には、大きなファイルを読み込む問題が解決されました。