在this document中,引入了一种在ZODB中处理可变列表的方法,即通过重新分配列表来“使用可变属性,就好像它是不可变的”。我试图在OOBTree结构中创建一个简单但相当长的反向索引,其中值是列表。受上述方法的启发,在不使用Persistentlist或其他任何内容的情况下,我只需将“append”替换为重新分配列表,并且它工作正常,并且生成的数据库文件非常小。我查了一下,显然索引没有任何问题,但我对此并不确定。这真的很容易吗?任何建议都将不胜感激。
以下是我用ZODB创建倒排索引的一些代码片段:
#......
root['idx']=OOBTree()
myindex = root['idx']
i=0
#.....
doc = cursor.first()
while doc:
docdict = {}
for word in doc.words():
docdict[word]=docdict.setdefault(word,0)+1
for (word,freq) in docdict.iteritems():
i+=1
if word in myindex:
myindex[word]= myindex[word]+ [(doc[0],freq)]
# This seems to work just fine.
# This is where I'm confused. Can this really work all right?
else:
myindex[word]=[(doc[0],freq)] # This list is not a PersistentList.
if i % 200000 == 0: transaction.savepoint(True)
doc =cursor.next()
docs.close()
transaction.commit()
#......
答案 0 :(得分:0)
是的,它真的很容易。
Persistent
基类覆盖__setattr__
挂钩,以检测何时需要提交到数据库的更改。对可变属性(例如列表)的更改不使用__setattr__
挂钩,因此不会被检测到。
最简单的方法是使用演示类来显示它:
>>> class Demo(object):
... def __setattr__(self, name, value):
... print 'Setting self.{} to {!r}'.format(name, value)
... super(Demo, self).__setattr__(name, value)
...
>>> d = Demo()
>>> d.foo = 'bar'
Setting self.foo to 'bar'
>>> d.foo = 'baz'
Setting self.foo to 'baz'
>>> d.foo
'baz'
>>> d.spam = []
Setting self.spam to []
>>> d.spam.append(42)
>>> d.spam
[42]
请注意d.spam.append()
调用不的结果如何导致打印输出; .append()
调用在列表中直接 ,而不在父Demo()
实例上。
重新分配 被检测到:
>>> d.spam = d.spam
Setting self.spam to [42]
通过直接设置Persistent
标志向_p_changed
发出更改信号的另一种方式:
myindex._p_changed = True
如果您怀疑是否检测到您的更改,您还可以测试该标记:
assert myindex._p_changed, "Oops, no change detected?"
如果AssertionError
为myindex._p_changed
(或许False
),则会引发0
;只有在当前交易开始后未检测到任何变化的情况下才会出现这种情况。