Python 最小化加载多对多关系的性能问题

Python 最小化加载多对多关系的性能问题,python,sql,orm,many-to-many,flask-sqlalchemy,Python,Sql,Orm,Many To Many,Flask Sqlalchemy,我一直在标记一个非常大的语料库。每个单格可以出现在多个注释中多次。我将Comment.id存储在一个列表中,该列表在数据库中每25万个新计数的Unigram中附加一个Unigram。我想知道的是,是否有一种方法可以扩展注释id列表——或类似的数据结构——而无需查询和加载与Unigram关联的现有注释列表(它可以有数千条)。还是没有办法绕过缓慢的IO 这是我的型号代码: comments = db.Table('ngrams', db.Column('unigram_id', db.Str

我一直在标记一个非常大的语料库。每个单格可以出现在多个注释中多次。我将Comment.id存储在一个列表中,该列表在数据库中每25万个新计数的Unigram中附加一个Unigram。我想知道的是,是否有一种方法可以扩展注释id列表——或类似的数据结构——而无需查询和加载与Unigram关联的现有注释列表(它可以有数千条)。还是没有办法绕过缓慢的IO

这是我的型号代码:

comments = db.Table('ngrams',
    db.Column('unigram_id', db.String, db.ForeignKey('comment.id')),
    db.Column('comment_id', db.String, db.ForeignKey('unigram.id')))

class Unigram(db.Model):
    id = db.Column(db.String, primary_key=True, unique=True)
    times_occurred = db.Column(db.Integer)
    occurs_in = db.relationship('Comment', secondary=comments,
                    backref=db.backref('unigrams', lazy='dynamic'))

class Comment(db.Model):
    id = db.Column(db.String, primary_key=True, unique=True)
    creation_time = db.Column(db.DateTime)
以及在中添加新计数和Comment.id的代码:

current = Unigram.query.filter(Unigram.id == ngram).first()
if current:
    current.times_occurred += counts[ngram]['count']
    current.occurs_in.extend(counts[ngram]['occurences'])
else:
    current = Unigram(ngram, counts[ngram]['count'],
                  counts[ngram]['occurences'])
    db.session.add(current)

你具体问题的答案(我认为):

relationship()的默认行为是完全加载集合 中的项目数。。。支持管理大型数据库的关键功能 集合就是所谓的“动态”关系。这是relationship()的一种可选形式,它在访问时返回一个查询对象来代替集合

看起来SQLAlchemy确实支持不必读取集合来修改它。因此,
lazy='dynamic'
是正确的。问题可能是您只在backref上有它。尝试以下两种变体:

occurs_in = db.relationship('Comment', secondary=comments, 
    lazy='dynamic', backref=db.backref('unigrams'))

occurs_in = db.relationship('Comment', secondary=comments, 
    lazy='dynamic', backref=db.backref('unigrams', lazy='dynamic'))
另外,您也可以尝试使用
lazy='noload'
。因为您只是在索引期间写入表,所以这将起到相同的作用

现在,更广泛的问题是:为什么要这样做?这样做会令人沮丧,即使在你解决了这个小问题之后。一些想法

使用正确的工具来完成这项工作:Sphinx、ElasticSearch、Lucene、Solr、Xapian,其中任何一个都可以非常彻底地处理文本索引问题,而且比不使用专门工具处理它要好得多。Sphinx执行速度特别快,索引速度达到每秒数百兆字节,查询一个单词包含多少文档通常需要一到两毫秒(不管语料库大小)

如果您正在执行一次性脚本或测试代码,而不是设置生产系统,并且出于某种原因不想使用正确的工具,那么请在内存中执行所有操作,不要使用SQL。在python中使用普通字典,并在运行之间将它们保存为ramdisk上的pickle文件。买更多的内存,它比你的时间便宜。这是在文本语料库上测试统计思想的一种不错的方法


如果出于某种原因(为什么?)。最好的方法是,以适当的格式准备一个数据转储(作为文本文件),并一次性将其加载到数据库中(使用类似MySQL中的
load data infle
,或数据库中的等效项)。这要快几个数量级。对于每个unigram,运行单个插入查询的速度很容易达到1000倍。如果您以正确的方式组织了表,您以后仍然可以通过SQLAlchemy访问数据,但是在为文本编制索引时,您希望绕过它。

您能澄清一下
。。。数据库每25万新计数的单位格…
?你的意思是每25万新格更新一次列表?您还可以谈谈数据集,它是实时数据集还是静态数据集(?)。通常这样的东西会变成稀疏矩阵,你不这样做有什么原因吗?@MattiLyra它是一个静态数据集。当我标记了~250K个单位格后,我会将计数从内存转移到数据库。在内存中,我将它们散列到一个字典中,其中键是unigram,值是另一个包含发生计数和注释ID的字典。从维基上关于稀疏矩阵的文章中,我认为字典属于这一类。