2012-02-22 50 views
27

Estoy tratando de analizar un gran archivo JSON (como http://eu.battle.net/auction-data/258993a3c6b974ef3e6f22ea6f822720/auctions.json) usando la biblioteca gson (http://code.google.com/p/google-gson/) en JAVA.JAVA - Mejor enfoque para analizar archivos JSON grandes (extra grandes)

Me gustaría saber cuál es la mejor aproximación para analizar este tipo de archivo grande (aproximadamente 80k líneas) y si conoce una buena API que pueda ayudarme a procesar esto. línea de

Una idea ...

  1. lectura por línea y deshacerse del formato JSON: pero eso es absurdo.
  2. reduzca el archivo JSON dividiendo este archivo en muchos otros: pero no encontré ninguna buena API de Java para esto.
  3. use este archivo directlly como base de datos no SQL, conserve el archivo y úselo como mi base de datos.

Realmente agradecería adices/help/messages/:-) Gracias.

+0

Una alternativa de Java EE: javax.json.stream.JsonParser – xonya

Respuesta

27

No necesita activar Jackson. Gson 2.1 introdujo una nueva interfaz TypeAdapter que permite la serialización y deserialización de secuencias mixtas en árbol.

La API es eficiente y flexible. Consulte Gson's Streaming doc para ver un ejemplo de combinación de árbol y vinculando modos. Esto es estrictamente mejor que los modos mixtos de transmisión y árbol; con el enlace no desperdicia la memoria creando una representación intermedia de tus valores.

Al igual que Jackson, Gson tiene API para omitir de manera recursiva un valor no deseado; Gson llama a esto skipValue().

+0

¡Lo verificaré! Gracias por compartir – Dax

+0

¿Hay un buen ejemplo de usar el 'TypeAdapter' para el análisis de flujo mixto en el análisis de árbol? Tengo un caso en el que quiero mezclarlo en una lista de objetos que se vuelve muy grande. El ejemplo en la documentación es la secuencia de análisis de una lista de 'mensajes' pero no muestra cómo vincularía ese analizador de flujo en un analizador de árbol. (Muestra cómo se vincula un analizador de árbol a un analizador de flujo) –

+0

Por ejemplo: tengo 'CustomType' para definir la asignación de objetos, y' CustomTypes extends ArrayList '. Hago un 'TypeAdapter ' que utiliza el mapeo de objetos para cada 'CustomType', pero simplemente devuelve una lista vacía al final para evitar almacenar toda la lista en la memoria (en su lugar, guárdelos en una base de datos). Y luego el objeto que contiene se analiza simplemente usando la asignación de objetos. –

25

Sugeriré que eche un vistazo a Jackson Api es muy fácil combinar las opciones de análisis de transmisión y modelo de árbol: puede moverse por el archivo como un todo de forma continua y luego leer objetos individuales en un árbol estructura.

Como example, tomemos la siguiente entrada:

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

Imagínese los campos siendo escasa o los registros que tienen una estructura más compleja.

El siguiente fragmento de código ilustra cómo se puede leer este archivo utilizando una combinación de análisis de secuencia y árbol. Cada registro individual se lee en una estructura en árbol, pero el archivo nunca se lee en su totalidad en la memoria, lo que permite procesar archivos JSON de un tamaño de gigabytes con una memoria mínima.

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

Como se puede adivinar, el nextToken() llama cada vez que da el siguiente evento de análisis: comenzar objeto, iniciar campo, iniciar matriz, comenzar objeto, ..., objeto final, ..., serie final , ...

La llamada jp.readValueAsTree() permite leer lo que está en la posición de análisis actual, un objeto o matriz JSON, en el modelo de árbol genérico JSON de Jackson. Una vez que tenga esto, puede acceder a los datos de forma aleatoria, independientemente del orden en que aparezcan las cosas en el archivo (en el ejemplo campo1 y campo2 no siempre están en el mismo orden). Jackson también admite el mapeo en sus propios objetos Java. Jp.skipChildren() es conveniente: permite omitir un árbol de objetos completo o una matriz sin tener que ejecutarse sobre todos los eventos que contiene.

+0

¡Tu código fue realmente útil! Lo ajusté a mi problema y finalmente pude deshacerme de mis excepciones de espacio de montón porque leí el archivo de una vez antes :-) –

Cuestiones relacionadas