2014-11-27 3 views
0

다음과 같은 응용 프로그램의 작업 로그 CSV 파일이 있다고 가정합니다. 이 CSV는 300 만 - 400 만 개의 행을 포함 할 수 있습니다. Java에서 CSV 데이터를 그룹별로 집계하는 방법은 무엇입니까?

Company, ActionsType, Action 
ABC, Downloaded, Tutorial 1 
ABC, Watched, Tutorial 2 
PQR, Subscribed, Tutorial 1 
ABC, Watched, Tutorial 2 
PQR, Subscribed, Tutorial 3 
XYZ, Subscribed, Tutorial 1 
XYZ, Watched, Tutorial 3 
PQR, Downloaded, Tutorial 1 

자바를 사용하여 아래 그림처럼 열 등의 회사 명 및 쇼 actionType 카운터에 의해 그룹화하여 그 데이터를 집계하는 어쨌든 방법이 있습니까?

Company, Downloaded, Watched, Subscribed 
ABC, 1, 2, 0 
PQR, 1, 0, 2 
XYZ, 0, 1, 1 

나는 OpenCSV를 사용하여 목록에로드 CSV 파일을 생각하지만, 데이터의 수백만의 csv 파일에 대한 효율적인가요?

+0

메모리가 확실한 경우 – MihaiC

+0

Idk 얼마나 좋은가요?하지만 그건 컴퓨터 비전 라이브러리입니다. CSV는 기본 목표가 아닙니다. 난 당신이 뭘하려고하는지 데이터베이스를 살펴 보겠습니다 http://stackoverflow.com/a/11624706/995891 – zapl

+0

당신은 자바에서만 이것을하고 싶니? 데이터베이스 솔루션은 어떻습니까? – MihaiC

답변

2

데이터를 집계하려는 경우 확실히 비효율적입니다. 대용량 데이터를 집계하려면 MapReduce를 확인해야합니다.

여기/맵리 듀스 오 승 해결책 :

import java.io.BufferedReader; 
import java.io.StringReader; 
import java.util.HashMap; 

public class CSVMapper { 

    public String transformCsv (String csvFile) { 
     return csvMapToString(getCsvMap(csvFile)); 
    } 

    private HashMap<String, Integer[]> getCsvMap (String csvFile) { 
     // <K,V> := <Company, [Downloaded, Watched, Subscribed]> 
     HashMap<String, Integer[]> csvMap = new HashMap<String, Integer[]>(); 
     BufferedReader reader = new BufferedReader(new StringReader(csvFile)); 
     String csvLine; 

     // Create map 
     try { 
      while ((csvLine = reader.readLine()) != null) { 
       String[] csvColumns = csvLine.split(","); 
       if (csvColumns.length > 0) { 
        try { 
         String company = csvColumns[0].trim(); 
         String actionsType = csvColumns[1].trim(); 
         Integer[] columnValues = csvMap.get(company); 

         if (columnValues == null) { 
          columnValues = new Integer[3]; 
          columnValues[0] = columnValues[1] = columnValues[2] = 0; 
         } 
         columnValues[0] = columnValues[0] + (actionsType.equals("Downloaded") ? 1 : 0); 
         columnValues[1] = columnValues[1] + (actionsType.equals("Watched") ? 1 : 0); 
         columnValues[2] = columnValues[2] + (actionsType.equals("Subscribed") ? 1 : 0); 

         if (!company.equals("Company")) 
          csvMap.put(company, columnValues); 
        } 
        catch (Exception nfe) { 
         //TODO: handle NumberFormatException 
        } 
       } 
      } 
     } 
     catch (Exception e) { 
      //TODO: handle IOException 
     } 
     return csvMap; 
    } 

    private String csvMapToString (HashMap<String, Integer[]> csvMap) { 
     StringBuilder newCsvFile = new StringBuilder(); 
     newCsvFile.append("Company, Downloaded, Watched, Subscribed\n"); 
     for (String company : csvMap.keySet()) { 
      Integer[] columnValues = csvMap.get(company); 
      newCsvFile.append(company + 
           ", " + Integer.toString(columnValues[0]) + 
           ", " + Integer.toString(columnValues[1]) + 
           ", " + Integer.toString(columnValues[2]) + "\n"); 
     } 
     return newCsvFile.toString(); 
    } 

    public static void main (String[] args) { 
     String csvFile = "Company, ActionsType, Action\n" + 
        "ABC, Downloaded, Tutorial 1\n" + 
        "ABC, Watched, Tutorial 2\n" + 
        "PQR, Subscribed, Tutorial 1\n" + 
        "ABC, Watched, Tutorial 2\n" + 
        "PQR, Subscribed, Tutorial 3\n" + 
        "XYZ, Subscribed, Tutorial 1\n" + 
        "XYZ, Watched, Tutorial 3\n" + 
        "PQR, Downloaded, Tutorial 1"; 

     System.out.println((new CSVMapper()).transformCsv(csvFile)); 
    } 
} 
1

CSV에서 수백만 항목을 다루므로 여기서는 파일을 구문 분석하는 데 Java을 사용하는 것이 최선의 방법이라고 생각하지 않습니다. sqlldr를 사용하여 데이터베이스에 CSV에서

A) 부하 모든 데이터 : 당신이 Oracle 데이터베이스가있는 경우

: 내가 대신 다음을 수행 할 다른 응용 프로그램을 만들 수 Java 또는 .NET을 사용

. http://www.thegeekstuff.com/2012/06/oracle-sqlldr/

b)는 로딩이 완료된 후 필요에 따라, 프로그램이, 이런 걸 데이터를 추출하는 쿼리를 실행합니다 : 그것은 SQLLDR에 대한 sqlldr .More 정보를 외부 프로세스 호출을 호출하여이 작업을 수행 할 것입니다 :

WITH T AS (SELECT COMPANY, ACTIONSTYPE FROM tmp_csv) 
SELECT * 
    FROM T PIVOT (COUNT (1) 
     FOR ACTIONSTYPE 
     IN ('Downloaded', 'Watched', 'Subscribed')) 

c)는, 쿼리의 ResultSet으로 원하는 것을 할 수 있도록 당신이 (후자는 쉽게 쿼리를 modyfing함으로써 달성된다 거기에서 결과를 조회 할 수 있습니다 다른 csv에 저장하거나 함께 새 테이블을 만들 이전에 create table as 성명으로)

,210

당신이 SqlServer 데이터베이스가있는 경우 : Oracle와 같은

같은 과정을하지만, 초기 csv에서 데이터를로드 할 수 bcp 유틸리티를 사용합니다. 여기에 더 많은 정보 : http://msdn.microsoft.com/en-us/library/ms162802.aspx

지금이 응용 프로그램 로그 CSV가 재생 될 때마다 실행할 수는 지속적인 데이터는, 그러나 당신이 원하는 쿼리 등의 보고서를 만들 수있는 데이터베이스에 저장 한 당신은에 처리를 추진하고 있기 때문에 데이터베이스의 경우 순수 java 솔루션보다 훨씬 효율적입니다.

java 솔루션을 고집하는 경우 병렬 처리를 사용하여 CSV의 모든 레코드를 읽고 처리하고 결과를 추가하고 새로운 csv 파일에 출력을 쓰는 것이 좋습니다.

1

예를 들어 행을 JSon으로 먼저 변환하면 CSV 항목을 MongoDB에 저장할 수 있다면 map/reduce 데이터 처리를 사용할 수 있습니다.

1

나의 제안은 스프링 배치와 같은 일괄 처리 프레임 워크를 사용하는 것입니다.

FieldExtractor 구현을 사용하여 줄의 각 토큰을 도메인 개체에 매핑 할 수 있습니다.

다음은 컬렉션에있는 항목을 보유하거나 사용자가 하나의 회사 만 유지하고 출력에 쓰고 다음 회사 (예 : this)에 대한 프로세스를 반복하는 사용자 정의 ItemWriter을 구현할 수 있습니다. 데이터베이스하지만 독자와 작가를 바꿀 수 있습니다.

관련 문제