Python MemoryError в словаре миллионов мест GeoNames?
Я пытаюсь создать словарь названий мест и информации из Geonames для использования в программе, которая читает документы, извлекает названия мест и выводит их информацию. Ключи - это имена местоположений, а список кортежей широты и долготы, код страны, класс пространственных объектов и идентификатор GeoName, соответствующие каждому имени (так как может быть несколько местоположений с одним и тем же именем), являются значениями. Вот примерная выдержка из словаря:
{'xixerella': [(('42.55327', '1.48736'), 'AD', 'PPL', '3038816'), (('42.55294', '1.48764'), 'AD', 'ADMD', '3038817')], 'fonts vives': [(('42.5', '1.56667'), 'AD', 'SPNG', '3038822')], 'roc del xeig': [(('42.56667', '1.48333'), 'AD', 'RK', '3038820')], 'costa de xurius': [(('42.5', '1.48333'), 'AD', 'SLP', '3038814')]}
Последний словарь имеет 9,088,105 ключей. Когда я пытаюсь записать его в файл с помощью pickle, чтобы я мог сослаться на него в другой программе, он выдает эту ошибку:
Python(763,0xa03871a8) malloc: *** mach_vm_map(size=50331648) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Traceback (most recent call last):
File "/Applications/Wing101.app/Contents/MacOS/src/debug/tserver/_sandbox.py", line 31, in <module>
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1370, in dump
Pickler(file, protocol).dump(obj)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 663, in _batch_setitems
save(v)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 600, in save_list
self._batch_appends(iter(obj))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 615, in _batch_appends
save(x)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 562, in save_tuple
save(element)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 581, in save_tuple
self.memoize(obj)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 247, in memoize
self.memo[id(obj)] = memo_len, obj
MemoryError:
Есть ли структура данных, которую я должен использовать вместо словаря? Что я могу сделать, чтобы сократить использование памяти?
Это моя программа как есть:
import csv
import sys
import pickle
geodict = {}
ignore = ["", " ", " ", " ", "-", " -", "- ", " - "]
csv.field_size_limit(sys.maxsize)
reader = csv.reader(open('allCountries-2.txt', 'rb'), delimiter='\t')
for row in reader:
loc = []
loc.append(row[2].lower())
if row[3] != '':
altnames = row[3].split(',')
for entry in altnames:
entry = "".join(x for x in entry if ord(x)<128)
entry = entry.lower()
if entry not in loc:
if entry not in ignore:
loc.append(entry)
geoid = row[0]
latlong = (row[4], row[5])
feature = row[7]
country = row[8]
for name in loc:
if name in geodict:
geodict[name].append((latlong, country, feature, geoid))
else:
geodict[name] = [(latlong, country, feature, geoid)]
with open('dict.txt', 'wb') as handle:
pickle.dump(geodict, handle)
Если вы не знакомы с форматом / содержимым файла Geonames: это текстовый файл с разделителями табуляции размером 1,14 ГБ, строка [2] - это имя местоположения в простых символах ASCII, строка [3] - это альтернативные имена местоположений (иногда нет alt names; я убираю не-ASCII bc, есть некоторые сумасшедшие акцентированные символы, китайские / японские / и т. д. символы, которые Python не любит) Если что-то еще неясно, просто спросите.
Пожалуйста помоги! Спасибо!
1 ответ
При работе с такими большими структурами данных, вам, вероятно, следует переключиться на потоковую рассылку. Он работает очень похоже на обычную рассолку, но загружает / сохраняет в потоковом (инкрементном) режиме, тем самым используя намного меньше памяти.