Nested Sets

В очередной раз столкнулся с ситуацией, когда данный алгоритм просто жизненно необходим и снова столкнулся с тем, что из предложенного в Сети нет ничего рабочего под PHP :(

класс от Joe Celko грешит ошибками при переносе ветки + адаптация под РНР4 и МуСкул4 меня не особо радует…

класс от Кузьмы Феськова вообще отказывается ветки переносить :( и уж чересчур привязан к собственным классам по работе с БД и пр. что не очень комфортно

в итоге вспомнив трактовку алгоритма и общие подходы сделал этот класс для работы с Nested Set, который в текущей (30 минутной) версии умеет создавать корень, добавлять/удалять/перемещать ветки и элементы…

Тесты проводил на двух деревьях, с двумя типами перемещения и несколькими типами удаления. Просьба если у кого есть свободное время — ознакомиться и указать тест-кейзы при которых класс себя не оправдывает.

Заранее спасибо :)

скачать класс

UPD (2008-01-18):

  • добавлена поддержка транзакций
  • добавлены методы получения ветки и обртного пути (breadcrumbs)
  • добавлено взаимодействие с внешним объектом работы с СУБД (использован личный класс-обертка над mysqli)

Немного теории.

Примечательность алгоритма Nested Sets (вложенные множества) выражается тем, что для выборки ветки или же всего дерева необходим всего один запрос к базе данных. Таким образом мы экономим ресурсы при работе с деревьями на момент выборки (а выборки в 90% случаев происходят гораздо чаще добавлений), хотя и немного теряем в производительности, добавляя новый элемент в структуру (из-за пересчета индексов левого и правого ключей,а так же индексной записи таблицы в БД).

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

Суть алгоритма состоит в том, что помимо связывания элементов по принципу id - parent_id, мы добавляем так называемые “левый” и “правый” ключи, которые и берут на себя всю основную работу при выборках. об алгоритме создания этих ключей можно почитать тут. Ну а для общего облегчения управлением дерева, в класс я добавил еще и поле level, указывающее глубину элемента в дереве и значительно расширяющее возможности работы алгоритма :)

Таким образом алгоритм Nested Sets, я считаю наиболее эффективным, если:

  • дерево имеет обширную структуру
  • выборок гораздо больше, чем изменений и перестановок веток
  • производительность приложения должна быть на максимальном возможном уровне

Если вы используете данные классы, то просьба указывать где-то на странице ссылку на эту статью. Спасибо

UPD (03.07.2008): Восстановили файл класса благодаря Александру Власову

Tags: , , , , , , , ,

Также рекомендую к прочтению:

22 Responses to “Nested Sets”

  1. Sergant Says:

    Пожалуйста, выложите ещё раз … ссылка не рабочая! =(

  2. Алексей Токарь Says:

    перезалил файлик — уже качает :) Спасибо за замечание :-[

  3. Sergant Says:

    Оперативненько, респект!!!

  4. Алексей Токарь Says:

    Usage Samples надо? :) Хотя думаю там и так вполне самодокументировано

    Единственно. Для инициализации объекта Db необходимо сделать изначальную конфигурацию:

    $db = Db::getInstance();
    $db->connect($options); //смотрим в класс

  5. Sergant Says:

    class DBNastedSet extends Collection
    ^^^^^^^^^^^ не нашел … , что наследуем ?..

  6. Алексей Токарь Says:

    сорь - выдирал из живого проекта - наследование тут уже не надо

  7. Matt Says:

    $child_cnt = $this->db->affected_rows;

    Что за affected_rows… нету такого в классе

  8. Алексей Токарь Says:

    в классе нет, так как сам класс представляет из себя надстройку над mysqli и вызывает собсна его (mysqli) методы и свойства через __call и __get

  9. Анатолий Says:

    А чем не подходит Pear::NestedSet?

  10. Алексей Токарь Says:

    а) никогда не любил PEAR. Он накладывает дополнительные ограничения на сервера, да и подобный принцип построения архитектуры мне не нра.
    б) РНР4
    в) в последней версии доступной для скачивания и установки слишком много багов и дополнительных пакетных зависимостей (мой зависит только от одного класса + от него элементарно избавиться)

  11. Анатолий Says:

    > Он накладывает дополнительные ограничения на сервера
    я не вникал.. А какие ограничения он накладывает?

  12. Алексей Токарь Says:

    существование PEAR пакетов + часто необходимость register_globals = on, что противоречит моей религии к примеру :)

  13. Вдадимир Селезнёв Says:

    Из минусов для PEAR NestedSet - приходится создавать отдельное подключение к БД или же передавать параметры созданного соединения, что ни есть хорошо т.к. можно было бы передать объект MDB2 и не давать “лишние данные”. Алексей, в PEAR можно подключать(require) необходимые пакеты как и сам PEAR.class и нет ограничений на сервер в том числе и существования PEAR пакетов - достаточно закачать и подключить один файл PEAR.class. Очень красиво было бы реализовать класс автора на PEAR::DB_DataObject - было бы удобно использовать.

  14. Алексей Токарь Says:

    http://www.phpdoctrine.org/

    на сегодняшний день, сказать больше чем по этой ссылке я ничего не могу :)

  15. Вдадимир Селезнёв Says:

    Пожалуй в doctrine всё есть - ORM и Nested set :-D

  16. Алексей Токарь Says:

    вот вот. ZendFramework + Doctrine и любой проект становится реальным за месяц…

  17. Вдадимир Селезнёв Says:

    http://www.phpdoctrine.org/blog/using-doctrine-zend-framework

  18. Алексей Токарь Says:

    у меня со стартом проблем не оказалось :) Doctrine + Zend = хорошая связка

  19. Вдадимир Селезнёв Says:

    Как раз в тему статья появилась “Integrating Zend Framework and Doctrine” через 3 дня после твоего поста ;)

  20. Алексей Токарь Says:

    автор не я :)) чесна :) за ссылку спасибо

  21. Алексей Says:

    а можно ссылочку обновить, плз. а то 404
    спасибо за статью :)

  22. standov Says:

    Какашко Ваша Doctrine, памяти выжирает просто немерянно, куча кросс-ссылок внутри, из-за чего освободить ее просто нереально, кучи, просто стада багов - не мудрено 0.10+ версия.

    ИМХО самый правильный ORM на пыхе это Propel 1.3 (именно 1.3 а не 1.2 из симфони), там кстати есть и реализация NestedSet, не совсем удачная но за 10 минут дотачивается до совершенства - все остальное, ИМХО, идеально

Leave a Reply

Введите следующие символы: