2016-01-12 7 views
6

के साथ जितनी जल्दी संभव हो सके डेटा डालने के लिए मैंने फ़ाइल पढ़ी और उससे ऑब्जेक्ट बनाया और पोस्टग्रेस्क्ल डेटाबेस में स्टोर किया। मेरी फ़ाइल में 100,000 दस्तावेज़ हैं जो मैंने एक फ़ाइल से पढ़ा है और इसे विभाजित किया है और अंततः डेटाबेस में संग्रहीत है। मैं List<> नहीं बना सकता और सभी दस्तावेज़ों को List<> में संग्रहीत नहीं कर सकता क्योंकि मेरी रैम कम है। डेटाबेस को पढ़ने और लिखने के लिए मेरा कोड नीचे दिया गया है। लेकिन मेरा जेवीएम हीप भरता है और अधिक दस्तावेज़ स्टोर करना जारी नहीं रख सकता है। डेटाबेस को कुशलता से फ़ाइल और स्टोर कैसे पढ़ा जाए।हाइबरनेट

public void readFile() { 
    StringBuilder wholeDocument = new StringBuilder(); 
    try { 
     bufferedReader = new BufferedReader(new FileReader(files)); 
     String line; 
     int count = 0; 
     while ((line = bufferedReader.readLine()) != null) { 
      if (line.contains("<page>")) { 
       wholeDocument.append(line); 
       while ((line = bufferedReader.readLine()) != null) { 
        wholeDocument = wholeDocument.append("\n" + line); 
        if (line.contains("</page>")) { 
         System.out.println(count++); 
         addBodyToDatabase(wholeDocument.toString()); 

         wholeDocument.setLength(0); 
         break; 
        } 
       } 
      } 
     } 
     wikiParser.commit(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      bufferedReader.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

public void addBodyToDatabase(String wholeContent) { 
    Page page = new Page(new Timestamp(System.currentTimeMillis()), 
      wholeContent); 
    database.addPageToDatabase(page); 
} 

public static int counter = 1; 

public void addPageToDatabase(Page page) { 
    session.save(page); 
    if (counter % 3000 == 0) { 
     commit(); 
    } 
    counter++; 
} 
+0

शायद तुम 'StringBuilder wholeDocument = नए StringBuilder() जोड़ने की जरूरत है, अपने छोरों –

+1

माध्यम से अंदर' कहीं, stringbuilder परिवर्तनशील, तो आप इस 'wholeDocument = wholeDocument.append क्या करने की जरूरत नहीं है कर रहे हैं (" \ n "+ लाइन); ', बस' wholeDocument.append (" \ n "+ line) का उपयोग करें;' –

+0

'प्रतिबद्ध()' क्या करता है? –

उत्तर

1

मैं @RookieGuy उत्तर का उपयोग करता हूं। stackoverflow.com/questions/14581865/hibernate-commit-and-flush

मैं

session.flush(); 
session.clear(); 

और अंत के बाद सभी दस्तावेजों को पढ़ने और उन्हें डेटाबेस में स्टोर का उपयोग

tx.commit(); 
session.close(); 

और बदल

wholeDocument = wholeDocument.append("\n" + line); 

को

wholeDocument.append("\n" + line); 
+0

मुझे लगता है कि आपने अपने प्रश्न का उत्तर दिया है। और मेरे लिए जवाब आपकी समस्या का समाधान करना चाहिए। अगर यह आपकी समस्या का समाधान करता है, तो आप अपना जवाब स्वीकार करना चाहेंगे। – Atul

0

मैं बहुत ज्यादा अपने डेटा file.It की संरचना के बारे में निश्चित नहीं हूँ, समझने में आसान होगा यदि आप अपनी फ़ाइल का एक नमूना प्रदान कर सकता होगा।

स्मृति खपत का मूल कारण फ़ाइल को पढ़ने/पुन: सक्रिय करने का तरीका है। एक बार कुछ पढ़ा जाता है, स्मृति में रहता है। आपको या तो java.io.FileInputStream या org.apache.commons.io.FileUtils का उपयोग करना चाहिए।

यहाँ आपरेशन बचाने के लिए और एक सौदे के लिए प्रतिबद्ध, java.io.FileInputStream

try (
     FileInputStream inputStream = new FileInputStream("/tmp/sample.txt"); 
     Scanner sc = new Scanner(inputStream, "UTF-8") 
) { 
    while (sc.hasNextLine()) { 
     String line = sc.nextLine(); 
     addBodyToDatabase(line); 
    } 
} catch (FileNotFoundException e) { 
    e.printStackTrace(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

यहाँ से पुनरावृति करने के लिए एक नमूना कोड org.apache.commons.io.FileUtils

File file = new File("/tmp/sample.txt"); 
LineIterator it = FileUtils.lineIterator(file, "UTF-8"); 
try { 
    while (it.hasNext()) { 
     String line = it.nextLine(); 
     addBodyToDatabase(line); 
    } 
} finally { 
    LineIterator.closeQuietly(it); 
} 
0

साथ दोहराना चाहते है आप किसी लेन-देन शुरू करना चाहिए करना एक नमूना कोड है । (बचाने के बाद लेनदेन शुरू मत करो!)। आप कैश द्वारा स्मृति खपत को बाहर करने के लिए StatelessSession का उपयोग करने का प्रयास कर सकते हैं।

और यह कोड

if (counter % 20 == 0) 

में और अधिक कम मूल्य, एक उदाहरण 20 के लिए, का उपयोग आप जहाँ तक संभव हो एक विधि के तर्क के रूप में StringBuilder पारित करने के लिए कोशिश कर सकते हैं।

8

सबसे पहले आपको यहां fork-join दृष्टिकोण लागू करना चाहिए।

मुख्य कार्य फ़ाइल को पार करता है और ExecutorService पर अधिकतम 100 आइटमों के बैच भेजता है। ExecutorService में कई कार्यकर्ता धागे होना चाहिए जो उपलब्ध डेटाबेस कनेक्शन की संख्या के बराबर हो। यदि आपके पास 4 सीपीयू कोर हैं, तो मान लें कि डेटाबेस अधिक संदर्भ स्विचिंग किए बिना 8 समवर्ती कनेक्शन ले सकता है।

आपको connection poolingDataSource कॉन्फ़िगर करना चाहिए और अधिकतम आकार के बराबर न्यूनतम आकार और 8 के बराबर होना चाहिए। कनेक्शन पूलिंग के लिए HikariCP या ViburDBCP का प्रयास करें।

फिर आपको JDBC batching कॉन्फ़िगर करने की आवश्यकता है। यदि आप MySQL का उपयोग कर रहे हैं, तो पहचान जनरेटर स्नान अक्षम कर देगा। यदि आप अनुक्रमों का समर्थन करने वाले डेटाबेस का उपयोग कर रहे हैं, तो सुनिश्चित करें कि आप उन्नत पहचानकर्ता जनरेटर का भी उपयोग करते हैं (वे हाइबरनेट 5.x में डिफ़ॉल्ट विकल्प हैं)।

इस तरह इकाई प्रविष्टि प्रक्रिया समान पार्सिंग थ्रेड के समानांतर और decoupled है। बंद करने से पहले सभी कार्यों को संसाधित करने के लिए मुख्य धागे को ExecutorService के लिए प्रतीक्षा करनी चाहिए।

2

असल में वास्तविक प्रोफाइलिंग किए बिना आपको यह सुझाव देना मुश्किल है और पता लगाएं कि आपका कोड धीमा या अक्षम है।

लेकिन वहाँ कई चीजें हम अपने कोड से देख सकते हैं

  1. आप StringBuilder अकुशलता से

    wholeDocument.append("\n" + line);wholeDocument.append("\n").append(line); बजाय

    के रूप में लिखा जाना चाहिए उपयोग कर रहे हैं क्या आप मूल लिखा अनुवाद किया जाएगा क्योंकि कर रहे हैं संकलक द्वारा whileDocument.append(new StringBuilder("\n").append(line).toString()) पर। आप देख सकते हैं आपके द्वारा बनाए गए कितना अनावश्यक StringBuilder रों :)

    हाइबरनेट

    का उपयोग कर मुझे यकीन है कि कैसे आप अपने session का प्रबंधन या नहीं कर रहा हूँ कि कैसे आप अपने commit() लागू किया, मैं आप इसे सही किया है मान में

  2. विचार, विचार करने के लिए अभी भी और बात है:

    • क्या आपने हाइबरनेट में बैच आकार को सही तरीके से स्थापित किया है? (hibernate.jdbc.batch_size) डिफ़ॉल्ट रूप से, जेडीबीसी बैच आकार लगभग 5 है। आप यह सुनिश्चित करना चाहते हैं कि आप इसे बड़े आकार में सेट करें (ताकि आंतरिक रूप से हाइबरनेट एक बड़े बैच में आवेषण भेज सके)।

    • यह देखते हुए कि आप बाद में उपयोग के लिए स्तर 1 कैश में संस्थाओं की जरूरत नहीं है, तो आप रुक-रुक कर सत्र flush() + clear()

      1. लिए उत्प्रेरक बैच आवेषण पिछले बिंदु में वर्णित
      2. स्पष्ट बाहर करने के लिए चाहते हो सकता है प्रथम स्तर कैश हाइबरनेट से
  3. स्विच दूर इस सुविधा के लिए।

    हाइबरनेट शांत है लेकिन यह सब कुछ के लिए पैनसिया नहीं है। यह देखते हुए कि इस सुविधा में आप केवल टेक्स्ट फ़ाइल सामग्री के आधार पर डीबी में रिकॉर्ड सहेज रहे हैं। न तो आपको किसी भी इकाई व्यवहार की आवश्यकता है, न ही आपको बाद में प्रसंस्करण के लिए प्रथम स्तर के कैश का उपयोग करने की आवश्यकता है, अतिरिक्त प्रोसेसिंग और स्पेस ओवरहेड दिए जाने पर यहां हाइबरनेट का उपयोग करने का कोई कारण नहीं है। मैन्युअल बैच हैंडलिंग के साथ बस जेडीबीसी करना आपको बहुत परेशानी बचाने जा रहा है।