Witam!
Napisałem program pobierający bazę danych z pewnego słownika. Zanim go uruchomię (a wykonanie programu zajmie kilka godzin) muszę być pewien, że w trakcie nic się nie wywali z powodu dużej ilości danych.
Najpierw pobieram wszystkie hasła do tablicy. Jest ich 190 tysięcy.
Potem do hashu o kluczu: “hasło” i wartości: “definicja” pobieram definicje haseł. Jest ich około 600 tysięcy (definicji).
Następnie dane te konwertuję do JSON i zapisuję do pliku.
Czy powyższy program nie zablokuje się np. z powodu “przeładowania pamięci tablicy”, albo wielkość pliku będzie za duża, żeby ją zapisać? Chcę uniknąć z góry takich problemów, a jest to kwestia czysto teoretyczna, którą cieżko sprawdzić w praktyce.
Pracuję na Windowsx64
Hola hola. Co innego wgrywać dumpa (jak rozumiem do bazy) a co innego w procesie rubiego pobierać 600 tysięcy rekordów. Przy takiej ilości jest wielce prawdopodobne, że zabraknie pamięci.
Dobra, odpaliłem to. Najwyżej stracę kilka godzin Dam znać, jak poszło i jaka jest wielkość pliku końcowego, jeśli się wszystko dobrze wykona.
Słowa już się zaindeksowały, a definicji jest pobrane 7.3%.
EDIT:
Ok, przy 11.6% wyrzuciło niemożność wykonania metody .inner_html na elemencie NIL, co by oznaczało, że się nie pobrał. Prawdopodobnie… Podzieliłem więc wszystko na 10 wykonań skryptu i właśnie leci pierwsze. Jeśli pierwsze się wykona, a drugie nie, to błąd nie leży w pamięci i wtedy zacznę szukać wadliwego wpisu.
EDIT2:
Dobra, błąd leży po stronie odbieranych danych.
Ja się tylko zastanawiam po co to robić? Wczytywanie tak dużego pliku JSON będzie trawło wieki.
Czy nie lepiej użyć zwykłej bazy relacyjnej albo nosqlowej? Jeśli dane byłyby jakoś bardzo powiązane wewnętrznie, to polecam moją Ruby Object Database http://github.com/apohllo/rod, którą stworzyłem właśnie do danych słownikowych. Ewentualnie można rozważyć użycie gemu do BerkleyDB (o ile coś aktualnego jest dostępne, bo kiepsko z tym bywało).
Jeśli przedstawisz szerzej zastosowanie, to mogę Ci coś doradzić, bo siedzę w temacie kilka lat.
No wlasnie - to typowe zastosowanie do klucz/wartosc serializowanego na dysk. Perl do czegos takiego dawal ‘tied hashes’ - prosta opakowywarka na hash-a tak, by operacje czytaj/zapisz trafialy z/na dysk. Jakies 15 lat temu
Scenariusz chyba nie jest aż tak prosty, bo na 190 tys. kluczy jest 600 tys. definicji, więc nie jest to 1-do-1. Ale tak czy owak fakt, że Perl w tym wypadku przewyższa Rubiego jest trochę niewygodny
Znaczy przerzuciłem się na MongoDB i wszystko wydaje się prostsze, ale z różnych powodów nie umiem tego ukończyć - skrypt działa kilka godzin i zawsze jakiś inny błąd. Wszystko staram się naprawiać na bieżąco… ostatni błąd to (już po przerzuceniu się na MongoDB) end of file - i jeszcze nie rozgryzłem, o co chodzi
log = File.open("path/to/log.txt","a")
# główna pętla
begin
# krok pętli
rescue Interrupt
break
rescue Exception => ex
log.puts ex
log.puts ex.backtrace
end
end
log.close
Dodatkowo możesz użyć gemu progress żeby monitorować ile czasu pozostało do końca zadania.
Warto też zainstalować sobie htop z stracem, żeby monitorować ile pamięci jest zajętej oraz jakie polecenie systemowe są wywoływane przez działający proces. Oczywiście monitorowanie logu mongo też nie jest bez znaczenia.
Ale jak zamierzasz potem szukać definicji? W każdej kolekcji z osobna? To trochę bez sensu. Użyj innego narzędzia.
A co do ramu, to fakt, że kolekcja na dysku ma 100MB nie oznacza, że 2GB ramu są wystarczające. Możesz mieć memory leak w samym skrypcie Rubiego. Polecałbym też użycie Rubiniusa, który znacznie lepiej zarządza pamięcią niż MRI.
Na razie najważniejsze dla mnie jest to po prostu pobrać. Jak już mi się to uda pobrać, to przepiszę na plik i ten plik poprzez PHP zapiszę sobie już w bazie MySQL - której chciałem użyć od samego początku, ale gem nie chciał współpracować z Ruby 2.0 na Windowsie… Bardziej chciałem po prostu sobie poćwiczyć coś
Mimo to dzięki za rady, już sobie wszystko zapisałem i wykorzystam je w przyszłych programach.
sqlite nie chce działać z Ruby 2.0, masa tematów na ten temat w Google jest.
mysql i mysql2 próbowałem, miałem masę problemów z kompilacją tak, żeby działało wszystko i dlatego przerzuciłem się na MongoDB.
Co do Rubiniusa - w przypadku Ruby wychodzenie w Windowsie poza domyślne, najłatwiej dostępne narzędzia, jest dalece nieoptymalne: wysiłek jest nieadekwatny do korzyści. Jeśli będę coś poważniejszego programował w Rubim, to zainstaluję - tak jak kiedyś - wirtualną maszynę z GNU/Linuxem. Na tę jednak chwilę zwyczajnie nie jest mi to potrzebne.