0

本文档中,介绍了 ZODB 中处理可变列表的方法,即通过重新分配列表来“使用可变属性,就好像它是不可变的一样”。我试图在 OOBTree 结构中创建一个简单但相当长的倒排索引,其中的值是列表。受上述方法的启发,没有使用 Persistentlist 或任何其他东西,我只是将“追加”替换为重新分配列表,它工作得很好,并且生成的数据库文件非常小。我检查了一下,显然索引没有任何问题,但我无法确定。真的可以这么简单吗?任何建议将不胜感激。

以下是我为使用 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()
#......
4

1 回答 1

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_changedFalse0

于 2013-10-25T17:19:48.093 回答