10.7 有关更多的索引维护工作
很明显,在shelf索引维护方面可能会需要做更多的工作。当使用简单的数据模型时,可以简单的为一篇文章的标签,日期和标题添加索引。这里为博客的另外一个访问层定义了两个索引。其中一个索引简单的列出了博客记录的所有键值。另外一个索引则基于博客标题提供相应键值。这里假设标题不是唯一的。我们会从3个方面来演示这个访问层的操作。以下是CRUD处理过程中的Create部分。
c1ass Access4( Access2 ):
def new( self, args, **kw ):
super().new( args, **kw )
self.database['_DB:Blog']= list()
self.database['_DB:Blog_Title']= defaultdict(list)
def add_blog( self, blog ):
self.max['Blog'] += 1
key= "Blog:(id)".format(id=self.max['Blog'])
blog._id= key
blog._post_list= []
self.database[bloq._id]= blog
self.darabase['_DB:Blog'].append( blog._id )
blog_title= self.database['_DB:Blog_Title']
blog_title[blog.title].append( blog._id )
self.database['_DB:Blog_Title']= blog_title
return blog
我们添加了两个索引:一个简单的Blog键列表和另一个保存了与某个给定标题相关的键的defaultdict。如果每个标题都是唯一的,那么所有的列表都是单例的。如果标题不唯一,那么每个标题都会有一个Blog键的列表。
当添加Blog实例时,也需要更新这两个索引。Blog键的简单列表通过追加一个新键然后保存到 shelf 上的方式更新。标题索引需要从 shelf 上获取现存的defaultdict,然后将与Blog标题匹配的键列表追加到它的尾部,最后将defaultdict保存在shelf上。下面的代码展示了CRUD中U(更新)的部分。
def update_blog( self, blog ):
"""Replace this Blog; update index."""
self.database[blog._id]= blog
blog_title= self.database['_DB:Blog_Title']
# Remove key from index in old spot.
empties= []
for k in blog_title:
if blog._id in blog_title[k]:
blog_title[k].remove( blog._id )
if len(blog_title[k]) == 0: empties.append( k )
# Cleanup zero-length lists from defaultdict.
for k in empties:
del blog_title[k]
# Put key into index in new spot.
blog_title[blog.title].append( blog._id )
self.database['_DB:Blog_Title']= blog_title
当我们更新Blog对象时,我们可能会更改Blog属性的标题。如果实体中包含越来越多的属性和索引,我们可能希望可以比较修改后的值和shelf上的值,这样就能知道哪些属性被更改了。对于这个只有一个属性的简单实体,不需要任何比较就可以知道哪个属性被更改了。
这个操作的第1个部分是将Blog的键从索引中移除。由于还没有得到Blog.title属性之前的值,因此我们不能简单地基于旧的值移除键。取而代之的是,我们必须搜索所有Blog键的索引,并且将与标题相关的键删除。
| 标题唯一的Blog会让标题的键列表为空。我们也应该清理无用的标题。 |
一旦将与旧标题相关的键从索引中移除,就可以用新标题把键添加到索引中。最后的两行代码和一开始创建Blog时所用的相同。下面是一些查询处理的例子。
def blog_iter( self ):
return ( self.database[k] for k in self.database['_DB:Blog'] )
def blog_title_iter( self, title ):
blog_title= self.database['_DB:Blog_Title']
return ( self.database[k] for k in blog_title[title] )
blog_iter()方法函数通过从 shelf 上获取索引对象来遍历所有的Blog对象。blog_title_iter()方法函数用索引获取某个给定标题相关的Blog对象。当有许多标题不同的Blog对象时,这个方法可以快速地根据标题定位到一个Blog对象。
