2012-02-22 31 views
27

JAVAのgsonライブラリ(http://code.google.com/p/google-gson/)を使用して、巨大なJSONファイル(http://eu.battle.net/auction-data/258993a3c6b974ef3e6f22ea6f822720/auctions.jsonなど)を解析しようとしています。JAVA - 巨大な(余分な)JSONファイルを解析するための最善のアプローチ

この種類の大きなファイル(約80k行)を解析するための最良のアッチと、これを処理するのに役立つ良いAPIが分かっているかどうかを知りたいと思います。

ラインでいくつかのアイデア...

  1. 読取ラインとJSONフォーマットを取り除く:それはナンセンスです。
  2. このファイルを他の多くのファイルに分割してJSONファイルを小さくしてください:しかし、このために良いJava APIは見つかりませんでした。
  3. このファイルをdirectlly nonSqlデータベースとして使用し、ファイルを保存してデータベースとして使用します。

本当にありがとう助言/ヘルプ/メッセージ/ :-)- ありがとうございます。

+0

Java EE代替:javax.json.stream.JsonParser – xonya

答えて

27

ジャクソンに切り替える必要はありません。 Gson 2.1では、ツリーとストリーミングの混在したシリアル化とデシリアライゼーションを可能にする新しいTypeAdapterインターフェイスが導入されました。

APIは効率的で柔軟性があります。ツリーとバインディングモードを結合する例については、Gson's Streaming docを参照してください。これは、混合ストリーミングとツリーモードよりも厳密に優れています。拘束力を持つと、あなたの価値の中間表現を構築するための記憶を浪費することはありません。

ジャクソンのように、Gsonには不要な値を再帰的にスキップするAPIがあります。 GsonはこれをskipValue()と呼びます。

+0

私はこれをチェックします!共にありがとう – Dax

+0

'TypeAdapter'を混在したストリーム解析をツリー解析に使用する良い例はありますか?私は非常に大きなオブジェクトのリストにそれを混在させたい場合があります。このドキュメントの例では、 'Message'sのリストをストリーム解析していますが、そのストリームパーサをツリーパーサーにどのように結び付けるかは分かりません。 (これはツリーパーザをストリームパーサに結び付ける方法を示しています) –

+0

例:オブジェクトマッピングを定義する 'CustomType'、' CustomTypes extends ArrayList 'があります。それぞれの 'CustomType'に対してオブジェクトマッピングを使用する' TypeAdapter 'を作成しますが、最後に空のリストを返して、リスト全体をメモリに格納しないでください(代わりにデータベースに書き込む)。そして、オブジェクトを含んでいるオブジェクトは単にオブジェクトマッピングを使って解析されます。 –

25

Jackson Apiストリーミングとツリーモデルの解析オプションを組み合わせることは非常に簡単です:ファイル全体をストリーミング形式で移動し、個々のオブジェクトをツリーに読み込むことができます構造。 exampleとして

、のは、以下の入力をみましょう:

{ 
    "records": [ 
    {"field1": "aaaaa", "bbbb": "ccccc"}, 
    {"field2": "aaa", "bbb": "ccc"} 
    ] , 
    "special message": "hello, world!" 
} 

はフィールドだけがスパースである、またはレコードは、より複雑な構造を有する想像してみてください。

次のスニペットは、ストリームとツリーモデルの解析の組み合わせを使用してこのファイルを読み取る方法を示しています。個々のレコードはツリー構造で読み込まれますが、ファイル全体がメモリに読み込まれることはありません。そのため、最小限のメモリを使用しながら、1ギガバイトのJSONファイルを処理することができます。

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(); 
      } 
     }     
     } 
    } 

あなたが想像できるように、のnextToken()は、各時間を呼び出すには、次の構文解析イベントを提供します:オブジェクト、...、エンドオブジェクト、...、エンド・アレイを起動すると、アレイを起動し、フィールドを起動し、オブジェクトを開始します、...

jp.readValueAsTree()コールは、現在の解析位置にあるもの、JSONオブジェクトまたは配列をJacksonのジェネリックJSONツリーモデルに読み込むことを可能にします。一度これを行うと、ファイルに表示される順序に関係なく、ランダムにデータにアクセスできます(この例では、field1とfield2は必ずしも同じ順序ではありません)。 Jacksonは独自のJavaオブジェクトへのマッピングもサポートしています。 jp.skipChildren()は便利です。完全なオブジェクトツリーまたは配列を、そのオブジェクトに含まれるすべてのイベントで実行する必要なしにスキップできます。

+0

あなたのコードは本当に役に立ちました!私はそれを私の問題に当てはめ、最後にヒープスペースの例外を取り除くことができました。なぜなら、前にファイルを読み込んでいるからです:-) –

関連する問題