2012-12-11 2 views
2

나는 다음과 같은 형식의가 1.7g 파일을 읽어 내 응용 프로그램에서 다른 것을 실행하십시오.가속화 파일

나의 현재 코드는 다음과 같습니다

RandomAccessFile raf=new RandomAccessFile("/home/map.dat","r"); 
       raf.seek(0); 
       while(raf.getFilePointer()!=raf.length()){ 
         String name=raf.readUTF(); 
         long offset=raf.readLong(); 
         map.put(name,offset); 
       } 

이 완료하는 데 약 12 ​​분 소요 나는 이것이 내가 어떤 도움이나 포인터를 부탁드립니다 일을 더 나은 방법이 확신 해요.

감사 EJP 제안에서와 같이


업데이트

?

EJP 의견을 보내 주셔서 감사 드리며 귀하의 뜻대로 되길 바랍니다. 이

DataInputStream dis=null; 
    try{ 
    dis=new DataInputStream(new BufferedInputStream(new FileInputStream("/home/map.dat"))); 
    while(true){ 
     String name=dis.readUTF(); 
     long offset=dis.readLong(); 
     map.put(name, offset); 
    } 
    }catch (EOFException eofe){ 
     try{ 
     dis.close(); 
     }catch (IOException ioe){ 
     ioe.printStackTrace(); 
     } 
    } 
+1

프로파일 링 결과는 무엇을 말합니까? 어디에서 병목 현상이 발생합니까? –

+1

1.7G 키 값 쌍, 파일 대신 데이터베이스를 사용하지 않는 이유는 무엇입니까? – jlordo

+0

그 양의 데이터로 무엇을하고 싶습니까? 나는 당신이 이것에 비효율적 인 접근법을 사용하고 있을지도 모른다는 강한 느낌을 가지고 있습니다. –

답변

2

파일을 구성하여 제자리에서 사용할 수 있도록합니다. 즉 이러한 방식으로 로딩하지 않아도된다. 가변 길이 레코드가 있으므로 각 레코드의 위치 배열을 구성한 다음 키를 순서대로 배치하여 데이터에 대한 2 진 검색을 수행 할 수 있습니다. (또는 사용자 정의 해시 테이블을 사용할 수 있습니다.) 그런 다음 데이터가 실제로 데이터 객체로 변환되는 대신 파일에 저장된다는 사실을 숨기는 메소드로이를 래핑 할 수 있습니다.

이 모든 작업을 수행하면 "로드"단계가 중복되고 너무 많은 개체를 만들 필요가 없습니다.


이것은 긴 예제이지만 가능하면 무엇인지 보여줍니다.

import vanilla.java.chronicle.Chronicle; 
import vanilla.java.chronicle.Excerpt; 
import vanilla.java.chronicle.impl.IndexedChronicle; 
import vanilla.java.chronicle.tools.ChronicleTest; 

import java.io.IOException; 
import java.util.*; 

public class Main { 
    static final String TMP = System.getProperty("java.io.tmpdir"); 

    public static void main(String... args) throws IOException { 
     String baseName = TMP + "/test"; 
     String[] keys = generateAndSave(baseName, 100 * 1000 * 1000); 

     long start = System.nanoTime(); 
     SavedSortedMap map = new SavedSortedMap(baseName); 
     for (int i = 0; i < keys.length/100; i++) { 
      long l = map.lookup(keys[i]); 
//   System.out.println(keys[i] + ": " + l); 
     } 
     map.close(); 
     long time = System.nanoTime() - start; 

     System.out.printf("Load of %,d records and lookup of %,d keys took %.3f seconds%n", 
       keys.length, keys.length/100, time/1e9); 
    } 

    static SortedMap<String, Long> generateMap(int keys) { 
     SortedMap<String, Long> ret = new TreeMap<>(); 
     while (ret.size() < keys) { 
      long n = ret.size(); 
      String key = Long.toString(n); 
      while (key.length() < 9) 
       key = '0' + key; 
      ret.put(key, n); 
     } 
     return ret; 
    } 

    static void saveData(SortedMap<String, Long> map, String baseName) throws IOException { 
     Chronicle chronicle = new IndexedChronicle(baseName); 
     Excerpt excerpt = chronicle.createExcerpt(); 
     for (Map.Entry<String, Long> entry : map.entrySet()) { 
      excerpt.startExcerpt(2 + entry.getKey().length() + 8); 
      excerpt.writeUTF(entry.getKey()); 
      excerpt.writeLong(entry.getValue()); 
      excerpt.finish(); 
     } 
     chronicle.close(); 
    } 

    static class SavedSortedMap { 
     final Chronicle chronicle; 
     final Excerpt excerpt; 
     final String midKey; 
     final long size; 

     SavedSortedMap(String baseName) throws IOException { 
      chronicle = new IndexedChronicle(baseName); 
      excerpt = chronicle.createExcerpt(); 
      size = chronicle.size(); 
      excerpt.index(size/2); 
      midKey = excerpt.readUTF(); 
     } 

     // find exact match or take the value after. 
     public long lookup(CharSequence key) { 
      if (compareTo(key, midKey) < 0) 
       return lookup0(0, size/2, key); 
      return lookup0(size/2, size, key); 
     } 

     private final StringBuilder tmp = new StringBuilder(); 

     private long lookup0(long from, long to, CharSequence key) { 
      long mid = (from + to) >>> 1; 
      excerpt.index(mid); 
      tmp.setLength(0); 
      excerpt.readUTF(tmp); 
      if (to - from <= 1) 
       return excerpt.readLong(); 
      int cmp = compareTo(key, tmp); 
      if (cmp < 0) 
       return lookup0(from, mid, key); 
      if (cmp > 0) 
       return lookup0(mid, to, key); 
      return excerpt.readLong(); 
     } 

     public static int compareTo(CharSequence a, CharSequence b) { 
      int lim = Math.min(a.length(), b.length()); 
      for (int k = 0; k < lim; k++) { 
       char c1 = a.charAt(k); 
       char c2 = b.charAt(k); 
       if (c1 != c2) 
        return c1 - c2; 
      } 
      return a.length() - b.length(); 
     } 

     public void close() { 
      chronicle.close(); 
     } 
    } 

    private static String[] generateAndSave(String baseName, int keyCount) throws IOException { 
     SortedMap<String, Long> map = generateMap(keyCount); 
     saveData(map, baseName); 
     ChronicleTest.deleteOnExit(baseName); 

     String[] keys = map.keySet().toArray(new String[map.size()]); 
     Collections.shuffle(Arrays.asList(keys)); 
     return keys; 
    } 
} 

은 2GB의 원시 데이터를 생성하고 백만개의 조회를 수행합니다. 로딩과 룩업이 힙을 거의 사용하지 않는 방식으로 작성되었습니다. 이 (1) 대신에 (N LN) O로하지만 더 복잡한 구현 O 그대로 룩업 당 빠를 것이다 해시 테이블 룩업을 이용하여 (1 < < MB)

ls -l /tmp/test* 
-rw-rw---- 1 peter peter 2013265920 Dec 11 13:23 /tmp/test.data 
-rw-rw---- 1 peter peter 805306368 Dec 11 13:23 /tmp/test.index 

/tmp/test created. 
/tmp/test, size=100000000 
Load of 100,000,000 records and lookup of 1,000,000 keys took 10.945 seconds 

.

+0

+1 메모리 매핑 파일은 성능, 초기화 시간 및 메모리 소비를 완벽하게 혼합해야합니다. –

+1

OP가 파일을 변경할 수없는 경우 이런 종류의 구조를 가진 인덱스 파일을 생성하여이 방법을 사용할 수 있습니다. –

+1

@MarkoTopolnik 나는 그것을 '완벽'하다고 거의 묘사하지 않을 것이다. OP가 지금하고있는 것보다 더 많은 메모리, 훨씬 더 많은 I/O 및 훨씬 더 많은 실행 시간. 시작 시간 감소, 예. – EJP

4
  1. 이 FileInputStream에 감싸 BufferedInputStream을 감싸의 DataInputStream를 사용하여 잘못된 경우 정정 해줘.

  2. 반복마다 시스템 호출을 4 번 이상 수행하고, 길이와 현재 크기를 확인하고 문자열과 길이를 가져올 읽기 수를 알고있는 사용자는 얻을 때까지 readUTF() 및 readLong()을 호출하십시오. EOFException

+0

답변과 의견을 EJP에 보내 주시면 감사하겠습니다. 나는 이것을 시도하고 데이터를 업로드하는 데 약 5 분이 걸린다. DataInputStream을 사용했지만 EOFExcpetion을 기다리지 않고 대신 읽기 프로세스가 느려졌을 수도있는 sys 호출을 사용했습니다. – DotNet

+0

@DotNet 그랬습니다. 반복마다 시스템 호출을 추가했습니다. 내 방식대로 해봐. 8k 데이터 당 하나의 시스템 호출 만 있습니다. 확실히 차이. – EJP

+0

시스템 호출 "사용 가능"없이 총 시간 4 분 22 초. 다시 한 번 감사드립니다 – DotNet