Как я могу искать объекты с отсутствующим значением или None в качестве ключа?

Я хотел бы выполнить поиск в каталоге 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?


person manuele    schedule 26.06.2012    source источник
comment
pypi.python.org/pypi/Products.ZCatalog/3.0a2 – - последний zcatalog обеспечивает поддержку не запросов   -  person vangheem    schedule 27.06.2012


Ответы (2)


Вы можете выполнять поиск по обоим типам, но для поиска записей 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 возвращает набор идентификаторов каталога IISet и его длину; каждый является указателем на запись каталога, для которой в именованном индексе нет записи. Затем вы можете использовать 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)
person Martijn Pieters    schedule 27.06.2012

Спасибо Аго. На самом деле, читая ссылку, которую вы предлагаете, я обнаруживаю, что это невозможно без уловки. Я сообщаю из pypi:

Обратите внимание, что отрицательная фильтрация индекса по-прежнему ограничивает элементы теми, которые имеют значение в индексе. Таким образом, с 10 документами, 5 из которых находятся в индексе foo со значением 1, запрос не 1 не вернет элементов вместо 5 элементов без значения. Вам нужно индексировать фиктивное значение/значение по умолчанию, если вы хотите учитывать все элементы для определенного индекса.

Поэтому необходимо указать значение по умолчанию для вашего элемента и искать его.

person manuele    schedule 27.06.2012