2011-07-28 16 views
14

Tengo una aplicación de servidor de Java que descarga archivos CSV y los analiza. El análisis puede tomar de 5 a 45 minutos, y ocurre cada hora. Este método es un cuello de botella de la aplicación, por lo que no es una optimización prematura. El código hasta ahora:Análisis de CSV rápido

 client.executeMethod(method); 
     InputStream in = method.getResponseBodyAsStream(); // this is http stream 

     String line; 
     String[] record; 

     reader = new BufferedReader(new InputStreamReader(in), 65536); 

     try { 
      // read the header line 
      line = reader.readLine(); 
      // some code 
      while ((line = reader.readLine()) != null) { 
       // more code 

       line = line.replaceAll("\"\"", "\"NULL\""); 

       // Now remove all of the quotes 
       line = line.replaceAll("\"", "");  


       if (!line.startsWith("ERROR"){ 
        //bla bla 
        continue; 
       } 

       record = line.split(","); 
       //more error handling 
       // build the object and put it in HashMap 
     } 
     //exceptions handling, closing connection and reader 

¿Existe alguna biblioteca que me ayude a acelerar las cosas? ¿Puedo mejorar el código existente?

+2

¿Qué tan grande es el archivo? ¿Y has intentado perfilar tu código? Esto le dará su cuello de botella y una idea clara de dónde mejorar. No me sorprendería que sea su red el principal problema. También eche un vistazo a http://commons.apache.org/sandbox/csv/ en lugar de construir el analizador usted mismo. – joostschouten

+0

Estoy creando perfiles en este momento y soy consciente de que gran parte del tiempo se debe a la conexión de red. Quiero mejorar el análisis primero porque con la red necesito cambiar la arquitectura. (Mi estimación es que un análisis más rápido puede mejorar el tiempo de carga en un 10-15%). –

+0

Suena justo. Utilice un analizador csv, ya que estos ya están optimizados y es probable que se encuentre con problemas de escape e i18n en el camino que no quiere preocuparse. Buena suerte. – joostschouten

Respuesta

18

Apache Commons CSV

Ha visto Apache Commons CSV?

Advertencia Sobre la utilización de split

Otra cosa a tener en cuenta es que split sólo devuelve una vista de los datos, lo que significa que el objeto original line no es elegible para la recolección de basura, mientras que hay una referencia a cualquiera de sus puntos de vista. Quizás hacer una copia defensiva ayudará? (Java bug report)

+0

+1 por error y voy a probar apache. –

13

opencsv

Tome un vistazo a opencsv.

Esta publicación de blog, opencsv is an easy CSV parser, tiene un uso de ejemplo.

+0

Ver comentarios sobre [respuesta similar de hermanos] (http://stackoverflow.com/a/6857291/642706). –

2

opencsv

Usted debe echar un vistazo a OpenCSV. Esperaría que tengan optimizaciones de rendimiento.

+0

Tenemos muy mala experiencia con opencsv. encontramos que es lento y con errores. Terminé perdiendo medio día y reemplazándolo por completo. – Guy

+0

bien ... es posible que desee agregar más detalles para que esta información sea relevante. ¿Qué problemas tuviste? ¿Qué versión usaste? ¿Qué otro marco elegiste? Me pregunto porque lo he visto en más de un proyecto en el que hizo un buen trabajo. – Kai

+0

El problema principal era que devolvía una cantidad incorrecta de campos (es decir, obtuve una cadena de 2 campos [] en una línea de 10 campos) para ciertas líneas. Nunca llegué a entender por qué sucedió, pero supongo que se relaciona de alguna manera con el mal análisis de utf-8. Lo he reemplazado con mi propia línea de lectura por línea, String.split en cada línea (me doy cuenta de que aquí hay consideraciones de memoria), que terminaron funcionando entre un 15% y un 30% más rápido. Estaba usando opencs v2.3 (java) – Guy

5

Además de las sugerencias anteriores, creo que puede intentar mejorar su código utilizando algunos subprocesos y simultaneidad.

siguiente es el breve análisis y la solución sugerida

  1. A partir del código parece que usted está leyendo los datos por la red (más posiblemente apache-common-httpclient lib).
  2. Debe asegurarse de que el cuello de botella que está diciendo no se encuentre en la transferencia de datos a través de la red.
  3. Una forma de verlo es simplemente volcar los datos en algún archivo (sin análisis) y ver cuánto se necesita. Esto le dará una idea de cuánto tiempo realmente se gasta en el análisis (en comparación con la observación actual).
  4. Ahora eche un vistazo a cómo se usa el paquete java.util.concurrent. Algunos de los enlaces que puede usar son (1, 2)
  5. Lo que puede hacer es que las tareas que realiza en for loop se pueden ejecutar en un hilo.
  6. El uso de threadpool y la concurrencia mejorarán en gran medida su rendimiento.

Aunque la solución implica un poco de esfuerzo, pero al final esto te ayudará.

+0

si el cuello de botella se transfiere a través de la red, debería considerar especificar el encabezado gzip –

5

El problema de su código es que está usando replaceAll y split, que son operaciones muy costosas. Definitivamente debería considerar el uso de un analizador/lector de csv que realice un análisis de una sola pasada.

Hay un punto de referencia en github

https://github.com/uniVocity/csv-parsers-comparison

que, lamentablemente, se corrió bajo java 6. El número son ligeramente diferentes en virtud de Java 7 y 8. Estoy tratando de conseguir más datos de detalle de archivo diferente tamaño pero es un trabajo en curso

ver https://github.com/arnaudroger/csv-parsers-comparison

Cuestiones relacionadas