【问题标题】:How can I look for objects with missing value or None as key?如何查找缺少值或无作为键的对象?
【发布时间】:2012-06-26 21:51:32
【问题描述】:

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

例如考虑后面的代码行:

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

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

【问题讨论】:

标签: plone zope catalog


【解决方案1】:

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

索引从一个对象中获取值,并索引它。如果存在AttributeError 或类似名称,则索引不存储该对象的任何内容,并且如果相同的字段是返回列的一部分,则在这种情况下,将给出MissingValue 以指示该索引为空字段。

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

搜索无

您可以在许多索引中搜索 None 就好了:

catalog(myKeywordIndex=None)

问题是大多数索引类型都忽略了None 作为一个值。因此,在日期和路径索引上搜索 None 将失败;他们忽略索引上的 None 和布尔索引;他们在索引时将 None 变为 False。

关键字索引也会忽略None,除非它是序列的一部分。如果索引方法返回[None],它会很高兴被索引,但None 本身不会。

字段索引确实在索引中存储None

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

catalog.uniqueValuesFor(indexname)

寻找缺失值

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

因此,我们可以计算这两组信息之间的差异。当您调用已发布的 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)
    )

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)

【讨论】:

    【解决方案2】:

    谢谢。实际上阅读您建议的链接,我发现没有技巧是不可能的。我从 pypi 报告:

    请注意,对索引的负过滤仍然会将项目限制为在索引中具有值的项目。因此,对于 10 个文档,其中 5 个在 foo 索引中,值为 1,对 not 1 的查询将不返回任何项目,而不是返回 5 个没有值的项目。如果要考虑特定索引的所有项目,则需要索引一个虚拟/默认值。

    所以有必要给你的项目一个默认值并寻找它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-18
      • 2015-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多