2015-01-08 12 views
5

में BZ2 JSON ट्विटर फ़ाइलों के साथ प्रभावी रूप से बड़ी (30GB +) TAR फ़ाइल को प्रभावी ढंग से कैसे पढ़ा जाए, मैं archive.org archive से ट्विटर डेटा प्राप्त करने और इसे डेटाबेस में लोड करने का प्रयास कर रहा हूं। मैं पहले एक विशिष्ट महीने के लिए सभी ट्वीट्स लोड करने का प्रयास कर रहा हूं, फिर ट्वीट्स के लिए चयन कर सकता हूं और केवल उन लोगों को मंचित कर सकता हूं जिनमें मुझे रूचि है (जैसे लोकेल, या हैशटैग)।पोस्टग्रेएसक्यूएल

मैं जो कुछ भी ढूंढ रहा हूं उसे करने के लिए नीचे वर्णित स्क्रिप्ट को चलाने में सक्षम हूं, लेकिन मुझे एक समस्या है कि यह अविश्वसनीय रूप से धीमी है। यह लगभग आधे घंटे तक चलता है और केवल एक टीएआर फ़ाइल में आंतरिक .bz2 फ़ाइलों के ~ 6/50,000 को पढ़ता है।

एक उदाहरण टीएआर फ़ाइल से कुछ आंकड़े:

  • कुल आकार: ~ 30-40GB
  • भीतरी .bz2 फ़ाइलों की संख्या (फ़ोल्डर में व्यवस्थित): 50,000
  • आकार में से एक .bz2 फ़ाइल : ~ 600kb
  • एक निकाली गई JSON फ़ाइल का आकार: ~ 5 एमबी, ~ 3600 ट्वीट्स।

गति के लिए इस प्रक्रिया को अनुकूलित करते समय मुझे क्या देखना चाहिए?

  • क्या मुझे पाइथन में उन्हें बफर करने के बजाय फ़ाइलों को डिस्क में निकालना चाहिए?
  • क्या मुझे प्रक्रिया के एक हिस्से को बहुसंख्यक देखना चाहिए? इस प्रक्रिया का कौन सा हिस्सा इष्टतम होगा?
  • वैकल्पिक रूप से, क्या मैं वर्तमान में ऐसी स्क्रिप्ट के लिए अपेक्षाकृत सामान्य प्राप्त कर रहा हूं?

स्क्रिप्ट वर्तमान में मेरे सीपीयू का ~ 3% और ~ 6% मेरी रैम मेमोरी का उपयोग कर रही है।

किसी भी मदद की बहुत सराहना की जाती है।

import tarfile 
import dataset # Using dataset as I'm still iteratively developing the table structure(s) 
import json 
import datetime 


def scrape_tar_contents(filename): 
    """Iterates over an input TAR filename, retrieving each .bz2 container: 
     extracts & retrieves JSON contents; stores JSON contents in a postgreSQL database""" 
    tar = tarfile.open(filename, 'r') 
    inner_files = [filename for filename in tar.getnames() if filename.endswith('.bz2')] 

    num_bz2_files = len(inner_files) 
    bz2_count = 1 
    print('Starting work on file... ' + filename[-20:]) 
    for bz2_filename in inner_files: # Loop over all files in the TAR archive 
     print('Starting work on inner file... ' + bz2_filename[-20:] + ': ' + str(bz2_count) + '/' + str(num_bz2_files)) 
     t_extract = tar.extractfile(bz2_filename) 
     data = t_extract.read() 
     txt = bz2.decompress(data) 

     tweet_errors = 0 
     current_line = 1 
     num_lines = len(txt.split('\n')) 
     for line in txt.split('\n'): # Loop over the lines in the resulting text file. 
      if current_line % 100 == 0: 
       print('Working on line ' + str(current_line) + '/' + str(num_lines)) 
       try: 
        tweet = json.loads(line) 
       except ValueError, e: 
        error_log = {'Date_time': datetime.datetime.now(), 
           'File_TAR': filename, 
           'File_BZ2': bz2_filename, 
           'Line_number': current_line, 
           'Line': line, 
           'Error': str(e)} 
        tweet_errors += 1 
        db['error_log'].upsert(error_log, ['File_TAR', 'File_BZ2', 'Line_number']) 
        print('Error occured, now at ' + str(tweet_errors)) 
       try: 
        tweet_id = tweet['id'] 
        tweet_text = tweet['text'] 
        tweet_locale = tweet['lang'] 
        created_at = tweet['created_at'] 
        tweet_json = tweet 
        data = {'tweet_id': tweet_id, 
          'tweet_text': tweet_text, 
          'tweet_locale': tweet_locale, 
          'created_at_str': created_at, 
          'date_loaded': datetime.datetime.now(), 
          'tweet_json': tweet_json} 
        db['tweets'].upsert(data, ['tweet_id']) 
       except KeyError, e: 
        error_log = {'Date_time': datetime.datetime.now(), 
           'File_TAR': filename, 
           'File_BZ2': bz2_filename, 
           'Line_number': current_line, 
           'Line': line, 
           'Error': str(e)} 
        tweet_errors += 1 
        db['error_log'].upsert(error_log, ['File_TAR', 'File_BZ2', 'Line_number']) 
        print('Error occured, now at ' + str(tweet_errors)) 
        continue 

if __name__ == "__main__": 
    with open("postgresConnecString.txt", 'r') as f: 
     db_connectionstring = f.readline() 
    db = dataset.connect(db_connectionstring) 

    filename = r'H:/Twitter datastream/Sourcefiles/archiveteam-twitter-stream-2013-01.tar' 
    scrape_tar_contents(filename) 

उत्तर

8

एक टैर फ़ाइल में फाइलें स्थित हैं, इसकी एक अनुक्रमणिका नहीं है। इसके अलावा, एक टैर फ़ाइल में more than one copy of the same file हो सकता है। इसलिए, जब आप एक फ़ाइल निकालते हैं, संपूर्ण टैर फ़ाइल पढ़ी जानी चाहिए। फ़ाइल को ढूंढने के बाद भी, शेष टैर फ़ाइल को अभी भी यह जांचने के लिए पढ़ा जाना चाहिए कि बाद की प्रति मौजूद है या नहीं।

इससे सभी फ़ाइलों को निकालने के रूप में एक फ़ाइल का निष्कर्षण महंगा हो जाता है।

इसलिए, बड़ी टैर फ़ाइल पर tar.extractfile(...) का उपयोग न करें (जब तक आपको केवल एक फ़ाइल की आवश्यकता न हो या सब कुछ निकालने के लिए स्थान न हो)।

आप अंतरिक्ष है (और आधुनिक हार्ड ड्राइव का आकार दिया है, तो आप लगभग निश्चित रूप से करते हैं), या तो tar.extractall साथ या tar xf ... करने के लिए एक सिस्टम कॉल के साथ सब कुछ निकालने, और उसके बाद निकाली गई फ़ाइलों को प्रोसेस।

+0

मैन्युअल रूप से मैन्युअल रूप से निकालने के बाद कोड बहुत तेजी से चला गया: धन्यवाद। मैंने http://stackoverflow.com/questions/27847695/how-to-multithread-reading-dples-from-a-list-and-entering-into-डेटा "मल्टीथ्रेडिंग पर सहायता मांगने के लिए जोड़ा। क्या आप पॉइंटर्स ऑन यह, शायद? – MattV

+0

लिनक्स टैर कमांड एक फ़ाइल को निकालने या मेनिफेस्ट में पूरी अनजान सामग्री को लोड किए बिना मैनिफेस्ट को सूचीबद्ध क्यों कर सकता है जबकि पाइथन का टैरिफाइल ऐसा लगता है? मेरे परीक्षण में, पाइथन 2 जीबी मेमोरी को सिंगल पाने के लिए क्या मिला फाइल आउट, टैर कमांड केवल 200 केबी का इस्तेमाल किया।ऐसा लगता है कि पाइथन संस्करण तुलना में यह बहुत अक्षमता से कर रहा है। – PKKid

+0

@ पीकेकिड: आप [इस प्रभाव] देख रहे हैं (http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm)। अगर वह इसका उत्तर नहीं देता है, तो कृपया एक नया प्रश्न पोस्ट करें। – unutbu

संबंधित मुद्दे