如何查找缺少值或无键的对象?

man*_*ele 4 zope plone catalog

我想对缺少索引键值的对象的zope目录执行搜索.可能吗?

例如,考虑后续代码行:

from Products.CMFCore.utils import getToolByName
catalog = getToolByName(context, 'portal_catalog')
results = catalog.searchResults({'portal_type': 'Event', 'review_state': 'pending'})
Run Code Online (Sandbox Code Playgroud)

如果我对没有插入某个项目而不是portal_type或review_state的对象感兴趣,该怎么办?

Mar*_*ers 7

您可以搜索这两种类型,但要搜索MissingValue条目需要自定义处理内部目录数据结构.

索引从对象获取值,并将其编入索引.如果存在AttributeError或类似,则索引不存储该对象的任何内容,并且如果相同的字段是返回列的一部分,则在该情况下MissingValue将给出指示该字段的索引为空的a.

在以下示例中,我假设您有一个catalog指向站点的portal_catalog工具的变量; 例如,getToolByName(context, 'portal_catalog')或类似的结果.

正在搜索无

你可以在很多索引中搜索 None:

catalog(myKeywordIndex=None)
Run Code Online (Sandbox Code Playgroud)

问题是大多数索引类型都被忽略None为一个值.因此,搜索None将在Date和Path索引上失败; 他们在索引和布尔索引上忽略None; 索引时将None转为False.

关键字索引None也会被忽略,除非它是序列的一部分.如果索引方法返回[None]它将很乐意被索引,但None它自己将不会.

字段索引存储None在索引中.

请注意,每个索引都可以显示唯一值,因此您可以None通过调用以下内容来检查是否存在为给定索引存储的值:

catalog.uniqueValuesFor(indexname)
Run Code Online (Sandbox Code Playgroud)

搜索缺失值

这有点棘手.例如,每个索引都会跟踪它已编入索引的对象,以便在删除对象时从索引中删除数据.同时,目录会跟踪它作为整体索引的对象.

因此,我们可以计算出这两组信息之间的差异.这就是目录在调用已发布的API时所做的事情,但是对于这个技巧,没有这样的公共API.我们需要进入目录内部并为自己抓住这些设置.

幸运的是,这些都是BTree集,因此操作相对有效.我是这样做的:

from BTrees.IIBTree import IISet, difference

def missing_entries_for_index(catalog, index_name):
    # Return the difference between catalog and index ids
    index = catalog._catalog.getIndex(index_name)
    referenced = IISet(index.referencedObjects()) # Works with any UnIndex-based index
    return (
        difference(IISet(catalog._catalog.paths), referenced),
        len(catalog) - len(referenced)
    )
Run Code Online (Sandbox Code Playgroud)

missing_entries_for_index方法返回一个目录ID的IISet及其长度; each是指向目录记录的指针,其中命名索引没有条目.然后,您可以使用catalog.getpath它将其转换为对象的完整路径,或者用于catalog.getMetadataForRID获取元数据值的字典,或者用于catalog.getobject获取原始对象本身,或用于catalog._catalog[]获取目录大脑.

以下方法将为您提供目录结果集,就像您从常规目录搜索中获得的那样:

from ZCatalog.Lazy import LazyMap

def not_indexed_results(catalog, index_name):
    rs, length = missing_entries_for_index(catalog, index_name)
    return LazyMap(catalog._catalog.__getitem__, rs.keys(), length)
Run Code Online (Sandbox Code Playgroud)