Способ индексации объектной базы данных - PullRequest
5 голосов
/ 12 июля 2011

Я использую объектную базу данных (ZODB) для хранения сложных взаимосвязей между многими объектами, но сталкиваюсь с проблемами производительности.В результате я начал создавать индексы, чтобы ускорить поиск и вставку объектов.Вот моя история, и я надеюсь, что вы можете помочь.

Изначально, когда я добавлял объект в базу данных, я вставлял его в ветку, посвященную этому типу объекта.Чтобы предотвратить несколько объектов, представляющих одну и ту же сущность, я добавил метод, который будет перебирать существующие объекты в ветви, чтобы найти дубликаты.Сначала это работало, но по мере увеличения размера базы данных время, необходимое для загрузки каждого объекта в память и проверки атрибутов, росло экспоненциально и неприемлемо.

Чтобы решить эту проблему, я начал создавать индексы на основе атрибутов вобъект, чтобы при добавлении объекта он сохранялся как в ветви типа, так и в ветви индекса значения атрибута.Например, допустим, что я сохранял объект person с атрибутами firstName = 'John' и lastName = 'Smith', объект добавлялся к ветви типа объекта person и также добавлялся к спискам в пределах ветви индекса атрибута с ключами 'Джон 'и' Смит '.

Это сэкономило много времени при проверке дубликатов, поскольку новый объект можно было проанализировать, и нужно проверять только набор объектов, которые пересекаются в индексах атрибутов.

Однако я быстро столкнулся с другой проблемой, касающейся действий при обновлении объектов.Индексы необходимо будет обновить, чтобы отразить тот факт, что они могут быть неточными.Это требует либо запоминания старых значений, чтобы к ним можно было напрямую получить доступ к объекту, и удаления объекта, либо итерации по всем значениям типа атрибута, чтобы найти, а затем удалить объект.В любом случае производительность снова начинает быстро снижаться, и я не могу найти способ ее решить.

У вас уже были подобные проблемы?Что вы решили, или это просто то, с чем мне приходится сталкиваться при использовании OODBMS?

Заранее благодарен за помощь.

Ответы [ 2 ]

8 голосов
/ 13 июля 2011

Да, repoze.catalog хорош и хорошо документирован.

Вкратце: не делайте индексацию частью структуры вашего сайта!

  1. Посмотрите на использованиеиерархия контейнера / элемента для хранения и прохождения объектов элемента содержимого;планируйте иметь возможность обходить содержимое либо (а) путем (ребра графа выглядят как файловая система), либо (б) путем идентификации одноэлементных контейнеров в некотором определенном месте

  2. Определите свой контент, используя UUIDs RFC 4122 (тип uuid.UUID) или 64-разрядные целые числа.

  3. Используйте центральный каталог для индексации(например, repoze.catalog);каталог должен находиться в известном месте относительно корневого объекта приложения вашего ZODB.И ваш каталог, вероятно, будет индексировать атрибуты объектов и возвращать идентификаторы записей (обычно целые числа) по запросу.Ваша задача - сопоставить эти целочисленные идентификаторы (возможно, с помощью UUID) с каким-то физическим путем в базе данных, где вы храните контент.Помогает, если вы используете zope.location и zope.container для общих интерфейсов для прохождения графа вашего объекта из корня / приложения и обратно.

  4. Используйте обработчики zope.lifecycleevent для индексации содержимого и сохранения вещейfresh.

Проблема - обобщенная

ZODB слишком гибок: это просто постоянный граф объектов с транзакциями, но это оставляет место для вас, чтобы утонуть или поплытьв ваших собственных структурах данных и интерфейсах.

Решение - обобщенное

Обычно, просто выбирая уже существующие идиомы от сообщества вокруг ZODB, будут работать: обработчики zope.lifecycleevent, «контейнерный» обход с использованием zope.container и zope.location и что-то вроде repoze.catalog.

Более конкретно

Только когда вы исчерпали обобщенные идиомы и знаете, почему они не работают, попробуйте создать свои собственные индексы, используя различные вариантыBrees в ZODB.Я на самом деле делаю это больше, чем хочу признать, но обычно у меня есть для этого веские основания.

Во всех случаях держите ваши индексы (поиск, обнаружение) и структуру сайта (обход и хранение) разными.

Идиомы для проблемного домена

  • Master ZODB BTrees: вы, вероятно, хотите:

    • Для хранения объектов контента как подклассов Persistent в контейнерах, которые являются подклассамиOOBTree предоставляет контейнерные интерфейсы (см. Ниже).
    • Для хранения BTrees для вашего каталога или глобальных индексов или использования таких пакетов, как repoze.catalog и zope.index, чтобы абстрагировать эту деталь (подсказка: каталоги обычно хранят индексы как OIBTreesэто даст целочисленные идентификаторы записей для результатов поиска, тогда у вас, как правило, будет какая-то утилита отображения документов, которая преобразует эти идентификаторы записей в нечто, разрешимое в вашем приложении, например, в uuid (при условии, что вы можете перейти к графу в UUID) или в путь (как это делает каталог Zope2).
  • IMHО, не беспокойтесь о работе с интидами, ссылками на клавиши и т. Д. (Они менее идиоматичны и сложнее, если они вам не нужны).Просто используйте Catalog и DocumentMap из repoze.catalog, чтобы получить результаты в виде целого числа в uuid или в форме пути, а затем выясните, как получить ваш объект.Обратите внимание, что вам, скорее всего, понадобится какая-нибудь утилита / синглтон, которая выполняет поиск вашего объекта по идентификатору или uuid, возвращенному в результате поиска.

  • Используйте zope.lifecycleevent или аналогичный пакет, который предоставляет синхронное событиерегистрация обратных вызовов (обработчик).Эти обработчики вам следует называть всякий раз, когда для вашего объекта выполняется элементарное редактирование (вероятно, один раз за транзакцию, но не в механизме транзакций).

  • Изучение архитектуры компонентов Zope;не абсолютное требование, но, безусловно, полезно, даже если просто понять интерфейсы zope.interface вышестоящих пакетов, таких как zope.container

  • Понимание того, как Zope2 (ZCatalog) делает это: каталоги каталога для нескольких индексов или различных сортов, каждый из которых ищет запрос, у каждого есть специализированные структуры данных, и у каждого возвращаются последовательности идентификаторов целочисленных записей.Они объединяются по индексам каталогом, выполняющим пересечения множества, и возвращаются как ленивое отображение «мозговых» объектов, содержащих заглушки метаданных (каждый мозг имеет метод getObject () для получения фактического объекта содержимого).Получение реальных объектов из поиска по каталогу основывается на идиоме Zope2 использования путей из корневого объекта приложения для определения местоположения каталогизированного элемента.

0 голосов
/ 12 июля 2011

Подумайте об использовании хэша атрибута (что-то вроде hashCode () в Java), затем используйте 32-битное значение хеша в качестве ключа.У Python есть хеш-функция, но я не очень знаком с ней.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...