2014-10-16 10 views
13

Problem, który mam, polega na tym, że mam bardzo duży plik pikli (2.6 Gb), który próbuję otworzyć, ale za każdym razem, gdy to robię, pojawia się błąd pamięci. Zdaję sobie teraz sprawę, że powinienem użyć bazy danych do przechowywania wszystkich informacji, ale jest już za późno. Plik pikla zawiera daty i tekst z amerykańskiego rekordu Kongresu, który został przeszukany z Internetu (trwało około 2 tygodni). Czy istnieje sposób uzyskać dostęp do informacji, które rzuciłem do pliku pikle inkrementalnie lub sposób konwertowania pliku pikle do bazy danych sql lub coś innego, co można otworzyć bez konieczności ponownego wprowadzania wszystkich danych. Naprawdę nie chcę spędzić kolejnych 2 tygodni na ponownym przeszukiwaniu rekordu kongresowego i przypisaniu danych do bazy danych.Plik pikli zbyt duży, aby załadować

Dzięki kilka za pomoc

EDIT *

kod

na jak obiekt zostanie marynowane:

def save_objects(objects): 
    with open('objects.pkl', 'wb') as output: 
     pickle.dump(objects, output, pickle.HIGHEST_PROTOCOL) 

def Main(): 
    Links() 
    file = open("datafile.txt", "w") 
    objects=[] 
    with open('links2.txt', 'rb') as infile: 
     for link in infile: 
      print link 
      title,text,date=Get_full_text(link) 
      article=Doccument(title,date,text) 
      if text != None: 
       write_to_text(date,text) 
       objects.append(article) 
       save_objects(objects) 

Jest to program z błędem:

def Main(): 
    file= open('objects1.pkl', 'rb') 
    object = pickle.load(file) 
+0

Ile pamięci RAM ma urządzenie z uruchomionym programem? – IanAuld

+0

Skorzystaj z programu sqlite, aby uzbroić plik o wielkości 2.6 Gb, który jest bliski szaleństwa. Sqlite jest dość łatwy do obejrzenia;) – brunsgaard

+0

Udostępniaj dane, a ja go rozpakuję dla Ciebie lub wypożyczysz dużą maszynę AWS do pracy. Jestem całkiem pewny, że @IanAuld ma rację ... brakuje ci pamięci. – brunsgaard

Odpowiedz

8

Nie dodałeś swoich danych narastająco. Wyszukujesz swoje dane w sposób monolityczny i powtarzalny. Za każdym razem wokół pętli zniszczyłeś dane wyjściowe, które miałeś (open(...,'wb') niszczy plik wyjściowy) i ponownie zapisałeś wszystkie dane. Dodatkowo, jeśli twój program kiedykolwiek zatrzymał się, a następnie uruchomił ponownie z nowymi danymi wejściowymi, stare dane wyjściowe zostały utracone.

Nie wiem, dlaczego objects nie spowodował błędu braku pamięci podczas wytrawiania, ponieważ urósł do rozmiaru, który chce utworzyć obiekt, który chce utworzyć pickle.load().

Oto jak mogłeś utworzony plik ogórkowy przyrostowo:

def save_objects(objects): 
    with open('objects.pkl', 'ab') as output: # Note: `ab` appends the data 
     pickle.dump(objects, output, pickle.HIGHEST_PROTOCOL) 

def Main(): 
    ... 
    #objects=[] <-- lose the objects list 
    with open('links2.txt', 'rb') as infile: 
     for link in infile: 
      ... 
      save_objects(article) 

Wtedy można mieć stopniowo odczytu pliku ogórkowy tak:

import pickle 
with open('objects.pkl', 'rb') as pickle_file: 
    try: 
     while True: 
      article = pickle.load(pickle_file) 
      print article 
    except EOFError: 
     pass 

Wybory mogę myśleć to:

  • Spróbuj cPickle. To może pomóc.
  • Spróbuj strumieniowego-słone
  • Czytaj plik ogórkowy w środowisku 64-bitowym z partii i wiele RAM
  • ponownego indeksowania oryginalne dane, tym razem rzeczywiście stopniowo przechowywania danych lub przechowywanie go w bazie danych . Bez niewydolności ciągłego przepisywania pliku wyjściowego pikle, indeksowanie może tym razem przebiegać znacznie szybciej.
+1

dzięki. Uruchomiłem przeszukiwacz na jednym komputerze, a następnie spróbowałem wyświetlić plik pikle na innym komputerze. Działa na oryginalnym komputerze, który ma więcej pamięci. –

+5

Och, to odpowiedź jest oczywista: wyodrębnij dane z pliku pikle na oryginalnym komputerze. –

29

Wygląda na nieco marynowaną! ;-). Mam nadzieję, że po tym NIGDY NIE POTRZEBUJESZ PICKLE EVER. To po prostu nie jest bardzo dobry format przechowywania danych.

W każdym razie, dla tej odpowiedzi zakładam, że twoja klasa Document wygląda trochę tak.Jeśli nie, komentarz rzeczywistą Document klasy:

class Document(object): # <-- object part is very important! If it's not there, the format is different! 
    def __init__(self, title, date, text): # assuming all strings 
     self.title = title 
     self.date = date 
     self.text = text 

Anyways, zrobiłem kilka prostych danych testowych z tej klasy:

d = [Document(title='foo', text='foo is good', date='1/1/1'), Document(title='bar', text='bar is better', date='2/2/2'), Document(title='baz', text='no one likes baz :(', date='3/3/3')] 

Marynowane go w formacie 2 (pickle.HIGHEST_PROTOCOL dla Pythona 2.x)

>>> s = pickle.dumps(d, 2) 
>>> s 
'\x80\x02]q\x00(c__main__\nDocument\nq\x01)\x81q\x02}q\x03(U\x04dateq\x04U\x051/1/1q\x05U\x04textq\x06U\x0bfoo is goodq\x07U\x05titleq\x08U\x03fooq\tubh\x01)\x81q\n}q\x0b(h\x04U\x052/2/2q\x0ch\x06U\rbar is betterq\rh\x08U\x03barq\x0eubh\x01)\x81q\x0f}q\x10(h\x04U\x053/3/3q\x11h\x06U\x13no one likes baz :(q\x12h\x08U\x03bazq\x13ube.' 

i demontowane go pickletools:

>>> pickletools.dis(s) 
    0: \x80 PROTO  2 
    2: ] EMPTY_LIST 
    3: q BINPUT  0 
    5: ( MARK 
    6: c  GLOBAL  '__main__ Document' 
    25: q  BINPUT  1 
    27:)  EMPTY_TUPLE 
    28: \x81  NEWOBJ 
    29: q  BINPUT  2 
    31: }  EMPTY_DICT 
    32: q  BINPUT  3 
    34: (  MARK 
    35: U   SHORT_BINSTRING 'date' 
    41: q   BINPUT  4 
    43: U   SHORT_BINSTRING '1/1/1' 
    50: q   BINPUT  5 
    52: U   SHORT_BINSTRING 'text' 
    58: q   BINPUT  6 
    60: U   SHORT_BINSTRING 'foo is good' 
    73: q   BINPUT  7 
    75: U   SHORT_BINSTRING 'title' 
    82: q   BINPUT  8 
    84: U   SHORT_BINSTRING 'foo' 
    89: q   BINPUT  9 
    91: u   SETITEMS (MARK at 34) 
    92: b  BUILD 
    93: h  BINGET  1 
    95:)  EMPTY_TUPLE 
    96: \x81  NEWOBJ 
    97: q  BINPUT  10 
    99: }  EMPTY_DICT 
    100: q  BINPUT  11 
    102: (  MARK 
    103: h   BINGET  4 
    105: U   SHORT_BINSTRING '2/2/2' 
    112: q   BINPUT  12 
    114: h   BINGET  6 
    116: U   SHORT_BINSTRING 'bar is better' 
    131: q   BINPUT  13 
    133: h   BINGET  8 
    135: U   SHORT_BINSTRING 'bar' 
    140: q   BINPUT  14 
    142: u   SETITEMS (MARK at 102) 
    143: b  BUILD 
    144: h  BINGET  1 
    146:)  EMPTY_TUPLE 
    147: \x81  NEWOBJ 
    148: q  BINPUT  15 
    150: }  EMPTY_DICT 
    151: q  BINPUT  16 
    153: (  MARK 
    154: h   BINGET  4 
    156: U   SHORT_BINSTRING '3/3/3' 
    163: q   BINPUT  17 
    165: h   BINGET  6 
    167: U   SHORT_BINSTRING 'no one likes baz :(' 
    188: q   BINPUT  18 
    190: h   BINGET  8 
    192: U   SHORT_BINSTRING 'baz' 
    197: q   BINPUT  19 
    199: u   SETITEMS (MARK at 153) 
    200: b  BUILD 
    201: e  APPENDS (MARK at 5) 
    202: . STOP 

Wygląda skomplikowanie! Ale tak naprawdę nie jest tak źle. pickle jest w zasadzie maszyną stosu, każdy identyfikator ALL_CAPS, który widzisz, to kod opcode, który manipuluje wewnętrznym "stosem" w jakiś sposób do dekodowania. Gdybyśmy próbowali przeanalizować jakąś złożoną strukturę, byłoby to ważniejsze, ale na szczęście tworzymy prostą listę krotek. Cały ten "kod" polega na konstruowaniu paczki obiektów na stosie, a następnie przesunięciu całego stosu na listę.

Jedną rzeczą, na którą musimy zwrócić uwagę, są kody opcyjne "BINPUT"/"BINGET", które są rozproszone. Zasadniczo chodzi o "zapamiętywanie", aby zmniejszyć ślad danych, pickle zapisuje ciągi znaków z BINPUT <id>, a następnie, jeśli pojawią się ponownie, zamiast ponownie je wyrzucić, po prostu wstawia BINGET <id>, aby pobrać je z pamięci podręcznej.

Kolejna komplikacja! Jest więcej niż tylko SHORT_BINSTRING - jest normalne BINSTRING dla ciągów> 256 bajtów, a także kilka zabawnych wariantów Unicode. Założę się, że używasz Pythona 2 ze wszystkimi ciągami znaków ASCII. Ponownie, komentarz, jeśli nie jest to prawidłowe założenie.

OK, więc musimy przesyłać strumieniowo plik, dopóki nie trafimy na "\ 81" bajtów (NEWOBJ). Następnie musimy przeskanować do przodu, aż uderzymy w znak "(" (MARK), a następnie, dopóki nie trafimy na "u" (SETITEMS), odczytamy pary ciągów klucz/wartość - powinno być 3 pary łącznie, jedna dla Każde pole:

Więc, zróbmy to, oto mój skrypt do czytania danych marynarskich w modzie strumieniowej, daleki od doskonałości, ponieważ po prostu zhakowałem go dla tej odpowiedzi i trzeba go bardzo zmodyfikować, ale to dobry początek

pickledata = '\x80\x02]q\x00(c__main__\nDocument\nq\x01)\x81q\x02}q\x03(U\x04dateq\x04U\x051/1/1q\x05U\x04textq\x06U\x0bfoo is goodq\x07U\x05titleq\x08U\x03fooq\tubh\x01)\x81q\n}q\x0b(h\x04U\x052/2/2q\x0ch\x06T\x14\x05\x00\x00bar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterq\rh\x08U\x03barq\x0eubh\x01)\x81q\x0f}q\x10(h\x04U\x053/3/3q\x11h\x06U\x13no one likes baz :(q\x12h\x08U\x03bazq\x13ube.' 

# simulate a file here 
import StringIO 
picklefile = StringIO.StringIO(pickledata) 

import pickle # just for opcode names 
import struct # binary unpacking 

def try_memo(f, v, cache): 
    opcode = f.read(1) 
    if opcode == pickle.BINPUT: 
     cache[f.read(1)] = v 
    elif opcode == pickle.LONG_BINPUT: 
     print 'skipping LONG_BINPUT to save memory, LONG_BINGET will probably not be used' 
     f.read(4) 
    else: 
     f.seek(f.tell() - 1) # rewind 

def try_read_string(f, opcode, cache): 
    if opcode in [ pickle.SHORT_BINSTRING, pickle.BINSTRING ]: 
     length_type = 'b' if opcode == pickle.SHORT_BINSTRING else 'i' 
     str_length = struct.unpack(length_type, f.read(struct.calcsize(length_type)))[0] 
     value = f.read(str_length) 
     try_memo(f, value, memo_cache) 
     return value 
    elif opcode == pickle.BINGET: 
     return memo_cache[f.read(1)] 
    elif opcide == pickle.LONG_BINGET: 
     raise Exception('Unexpected LONG_BINGET? Key ' + f.read(4)) 
    else: 
     raise Exception('Invalid opcode ' + opcode + ' at pos ' + str(f.tell())) 

memo_cache = {} 
while True: 
    c = picklefile.read(1) 
    if c == pickle.NEWOBJ: 
     while picklefile.read(1) != pickle.MARK: 
      pass # scan forward to field instantiation 
     fields = {} 
     while True: 
      opcode = picklefile.read(1) 
      if opcode == pickle.SETITEMS: 
       break 
      key = try_read_string(picklefile, opcode, memo_cache) 
      value = try_read_string(picklefile, picklefile.read(1), memo_cache) 
      fields[key] = value 
     print 'Document', fields 
     # insert to sqllite 
    elif c == pickle.STOP: 
     break 

to poprawnie czyta moich danych testowych w formacie ogórka 2 (zmodyfikowany mieć długi łańcuch).

$ python picklereader.py 
Document {'date': '1/1/1', 'text': 'foo is good', 'title': 'foo'} 
Document {'date': '2/2/2', 'text': 'bar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is betterbar is better', 'title': 'bar'} 
Document {'date': '3/3/3', 'text': 'no one likes baz :(', 'title': 'baz'} 

Powodzenia!

Powiązane problemy