Python 使用pickle将巨大的bigram字典保存到文件

Python 使用pickle将巨大的bigram字典保存到文件,python,file,dictionary,pickle,Python,File,Dictionary,Pickle,我的一个朋友写了这个小节目。 textFile的大小为1.2GB(相当于7年的报纸)。 他成功地创建了字典,但无法使用pickle(程序挂起)将其写入文件 希望这有帮助。现在的策略改为使用mysql,因为sqlite无法工作(可能是因为它的大小)Pickle只用于编写完整(小)的对象。您的字典有点大,甚至无法保存在内存中,您最好使用数据库,这样您就可以逐个存储和检索条目,而不是一次存储所有条目 可以从Python中使用的一些好的、易于集成的单文件数据库格式是或其中之一。最后一个类似于字典(即,您

我的一个朋友写了这个小节目。
textFile
的大小为1.2GB(相当于7年的报纸)。 他成功地创建了字典,但无法使用pickle(程序挂起)将其写入文件


希望这有帮助。现在的策略改为使用mysql,因为sqlite无法工作(可能是因为它的大小)

Pickle只用于编写完整(小)的对象。您的字典有点大,甚至无法保存在内存中,您最好使用数据库,这样您就可以逐个存储和检索条目,而不是一次存储所有条目


可以从Python中使用的一些好的、易于集成的单文件数据库格式是或其中之一。最后一个类似于字典(即,您可以读取和写入键/值对),但将磁盘用作存储,而不是1.2 Gb的内存。

您真的需要内存中的全部数据吗?如果你想使用字典/pickle方法,你可以用简单的方式将其拆分,比如每年一个文件,每个月一个文件

另外,请记住,字典没有排序,您可能会遇到排序这一数据量的问题。如果您想搜索或排序数据,当然

无论如何,我认为前面提到的数据库方法是最灵活的方法,特别是从长远来看…

如果您真的非常想使用字典式语义,请尝试SQLAlchemy的
associationproxy
。以下(相当长的)代码段将词典翻译成
条目表中的键、值对。我不知道SQLAlchemy如何处理您的大词典,但SQLite应该能够很好地处理它

from sqlalchemy import create_engine, MetaData
from sqlalchemy import Table, Column, Integer, ForeignKey, Unicode, UnicodeText
from sqlalchemy.orm import mapper, sessionmaker, scoped_session, Query, relation
from sqlalchemy.orm.collections import column_mapped_collection
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.schema import UniqueConstraint

engine = create_engine('sqlite:///newspapers.db')

metadata = MetaData()
metadata.bind = engine

Session = scoped_session(sessionmaker(engine))
session = Session()

newspapers = Table('newspapers', metadata,
    Column('newspaper_id', Integer, primary_key=True),
    Column('newspaper_name', Unicode(128)),
)

entries = Table('entries', metadata,
    Column('entry_id', Integer, primary_key=True),
    Column('newspaper_id', Integer, ForeignKey('newspapers.newspaper_id')),
    Column('entry_key', Unicode(255)),
    Column('entry_value', UnicodeText),
    UniqueConstraint('entry_key', 'entry_value', name="pair"),
)

class Base(object):

    def __init__(self, **kw):
        for key, value in kw.items():
            setattr(self, key, value)

    query = Session.query_property(Query)

def create_entry(key, value):
    return Entry(entry_key=key, entry_value=value)

class Newspaper(Base):

    entries = association_proxy('entry_dict', 'entry_value',
        creator=create_entry)

class Entry(Base):
    pass

mapper(Newspaper, newspapers, properties={
    'entry_dict': relation(Entry,
        collection_class=column_mapped_collection(entries.c.entry_key)),
})
mapper(Entry, entries)

metadata.create_all()

dictionary = {
    u'foo': u'bar',
    u'baz': u'quux'
}

roll = Newspaper(newspaper_name=u"The Toilet Roll")
session.add(roll)
session.flush()

roll.entries = dictionary
session.flush()

for entry in Entry.query.all():
    print entry.entry_key, entry.entry_value
session.commit()

session.expire_all()

print Newspaper.query.filter_by(newspaper_id=1).one().entries
给予


一种解决办法是用泡菜代替泡菜。这是一个纯Python解决方案,保留了非常Python的语法。我认为这是下一步从搁置和他们的同类。它将处理您正在谈论的数据大小。其大小限制为每个字段2 GB(每个字段存储在单独的文件中)。

我从
http://coverartarchive.org
尽管下载这么多图像速度很慢,
pickle
在155MB的容量上没有问题:

$ ll
total 151756
-rw-rw-r--  1 rick rick 155208082 Oct 10 10:04 ipc.pickle

当我不再只为一张CD下载图像时,我会回来用更大的pickle限制更新这个答案。不幸的是,我还没有找到任何说明酸洗限制的地方…

如果你要处理大文件,为什么不使用数据库呢?另外,我看到您对同一个文件执行了两次for循环,这可能是多余的,并且增加了处理成本。为什么不描述一下您对示例输入文件所做的操作呢?ghostdog74,您可以看到2个语句,但在文件上只有一个循环:)在文件上迭代只是读取行(从实际位置),它不查找文件的开头。只需尝试一下(您的Python dict由磁盘上的DB支持,而不是RAM支持).Sqlite是一个完全关系数据库,而Berkeley DB不是,只是键/值。如果只是存储,我认为Berkeley是一个更好的选择,而如果您想进行一些查询并以更有条理的方式存储信息,sqlite则更合适。BerkeleyDB非常易变且难以管理,尤其是在数据量较大的情况下。即使对于单个字符串->字符串存储(BerkeleyDB就是这样),我也会使用SQLite,它会处理所有的BerkeleyDB管理。SQLite的作用不像字典。bsddb module()的Python页面说它不推荐使用。对于BSD DB,是否还有另一个未弃用的Python选项?列出了许多数据持久性模块。gdbm的
gdbm
模块看起来非常相似,并且仍然受支持,我会选择这个模块。我正在考虑在python中使用SQLite3。不过,我不确定你的答案中与
sqlalchemy
的关系。
{
 "Hello": {"World": 1, "munde": 1}, 
 "World": {"domination": 2},
 "Total": {"World": 1},
}
from sqlalchemy import create_engine, MetaData
from sqlalchemy import Table, Column, Integer, ForeignKey, Unicode, UnicodeText
from sqlalchemy.orm import mapper, sessionmaker, scoped_session, Query, relation
from sqlalchemy.orm.collections import column_mapped_collection
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.schema import UniqueConstraint

engine = create_engine('sqlite:///newspapers.db')

metadata = MetaData()
metadata.bind = engine

Session = scoped_session(sessionmaker(engine))
session = Session()

newspapers = Table('newspapers', metadata,
    Column('newspaper_id', Integer, primary_key=True),
    Column('newspaper_name', Unicode(128)),
)

entries = Table('entries', metadata,
    Column('entry_id', Integer, primary_key=True),
    Column('newspaper_id', Integer, ForeignKey('newspapers.newspaper_id')),
    Column('entry_key', Unicode(255)),
    Column('entry_value', UnicodeText),
    UniqueConstraint('entry_key', 'entry_value', name="pair"),
)

class Base(object):

    def __init__(self, **kw):
        for key, value in kw.items():
            setattr(self, key, value)

    query = Session.query_property(Query)

def create_entry(key, value):
    return Entry(entry_key=key, entry_value=value)

class Newspaper(Base):

    entries = association_proxy('entry_dict', 'entry_value',
        creator=create_entry)

class Entry(Base):
    pass

mapper(Newspaper, newspapers, properties={
    'entry_dict': relation(Entry,
        collection_class=column_mapped_collection(entries.c.entry_key)),
})
mapper(Entry, entries)

metadata.create_all()

dictionary = {
    u'foo': u'bar',
    u'baz': u'quux'
}

roll = Newspaper(newspaper_name=u"The Toilet Roll")
session.add(roll)
session.flush()

roll.entries = dictionary
session.flush()

for entry in Entry.query.all():
    print entry.entry_key, entry.entry_value
session.commit()

session.expire_all()

print Newspaper.query.filter_by(newspaper_id=1).one().entries
foo bar
baz quux
{u'foo': u'bar', u'baz': u'quux'}
$ ll
total 151756
-rw-rw-r--  1 rick rick 155208082 Oct 10 10:04 ipc.pickle