Skip to main content
 首页 » 编程设计

python之ZODB 中具有可变属性的对象的一致索引

2025年05月04日10kuangbin

我有一个 ZODB 安装,我必须在其中组织数百万个不同类型的对象。我有一个通用容器类 Table,其中包含 BTrees 以按属性或这些属性的组合对对象进行索引。数据一致性非常重要,因此我想强制执行,当我写入索引涵盖的任何属性时,索引会自动更新。所以一个简单的 obj.a = x 应该足以计算所有新的依赖索引条目,检查是否有任何冲突,最后写入索引和值。

一般来说,我很乐意为此使用一个库,所以我正在查看 repoze.catalog和 IndexedCatalog ,但对此并不十分满意。 IndexedCatalog 似乎已经死了很长一段时间,并且没有为对象的更改提供那种一致性。据我所知,repoze.catalog 似乎更常用和活跃,但也没有提供这种一致性。如果我在这里遗漏了什么,我很乐意听到它并且更愿意重用而不是重新发明。

所以,除了试图为问题找到一个库之外,我如何看待它,我必须拦截对带有描述符的数据对象属性的写访问,并让 Table 类发挥魔力改变指数。为此,描述符实例必须知道它们必须与哪些 Table 实例进行对话。当前的实现是这样的:

class DatabaseElement(Persistent): 
    name = Property(constant_parameters) 
    ... 
 
class Property(object): 
    ... 
    def __set__(self, obj, name, val): 
        val = self.check_value(val) 
        setattr(obj, '_' + name, val) 

生成这些 DatabaseElement 类时,数据库和其中的对象尚未创建。所以正如这个 nice answer 中提到的,我可能必须创建一些单例查找机制来查找 Table 对象,而不将它们作为实例化参数传递给 Property。有没有更优雅的方式?持久化描述符本身?欢迎任何建议和最佳实践示例!

请您参考如下方法:

所以我终于想通了自己。该解决方案分为三个部分。不需要丑陋的单例。 Table 提供检查冲突的逻辑,DatabaseElement 能够查找负责的 Table 而无需丑陋的解决方法和 Property 注意,在写入任何索引值之前更新索引。这里有一些片段,主要线索是 DatabaseElement 的表查找。我也没有在任何地方看到该记录。不错的额外功能:它不仅可以验证对单个值的写入,我还可以一次性检查多个索引值的更改。

class Table(PersistentMapping): 
    .... 
    def update_indices(self, inst, updated_values_dict): 
        changed_indices_keys = self._check_collision(inst, updated_values_dict) 
        original_keys = [inst.key(index) for index, tmp_key in changed_indices_keys] 
        for (index, tmp_key), key in zip(changed_indices_keys, original_keys): 
            self[index][tmp_key] = inst 
            try: 
                del self[index][key] 
            except KeyError: 
                pass 
 
 
class DatabaseElement(Persistent): 
    .... 
    @property 
    def _table(self): 
        return self._p_jar and self._p_jar.root()[self.__class__.__name__] 
 
    def _update_indices(self, update_dict, verify=True): 
        if verify: 
            update_dict = dict((key, getattr(type(self), key).verify(val))  
                                for key, val in update_dict.items() 
                                if key in self._key_properties) 
        if not update_dict: 
            return 
        table = self._table 
        table and table.update_indices(self, update_dict) 
 
 
class Property(object): 
    .... 
    def __set__(self, obj, val): 
        validated_val = self.validator(obj, self.name, val) 
        if self.indexed: 
            obj._update_indices({self.name: val}, verify=False) 
        setattr(obj, self.hidden_name, validated_val)