За последние 24 часа нас посетили 21755 программистов и 1013 роботов. Сейчас ищут 655 программистов ...

использовние графов для организации древовидной структуры.

Тема в разделе "PHP и базы данных", создана пользователем dark-demon, 16 апр 2007.

  1. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    использованная структура таблиц:
    [sql]create table mo_node_list (id integer primary key, parentid int, type int, name text, data text);
    create table mo_node_links (anc int, desc int);[/sql]
    +
    [sql]create index mo_node_links_anc on mo_node_links (anc);
    create index mo_node_links_desc on mo_node_links (desc);
    create index mo_node_list_parent on mo_node_list (parentid);[/sql]
     
  2. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    всё переписал... на объединения забил - всё сделал через подзапросы.
    тесткейс и сорцы: http://dark-demon.jino-net.ru/directree/
    вкратце по методам:
    в качестве параметров им можно передавать число-идентификатор, либо ассоциативный массив с полями как в таблице. лучше передавать массив, если он есть, ибо в первом случае некоторые методы формируют sql-подзапрос для получения нужных данных.

    методы формирующие sql-подзапросы, либо по возможности сразу возвращающие данные:
    SQLid - идентификатор узла
    SQLparent - идентификатор родителя узла
    SQLancs - список идентификаторов предков (исключая сам узел)
    SQLchilds - список непосредственных детей узла
    SQLdescsets - список внутренних узлов (то есть не, листьев) являющихся потомками узла (включая сам узел)
    SQLdescs - список всех потомков узла (исключая сам узел)

    пара геттеров:
    GETancs - получить всех предков в виде массива ассоциативных массивов, с опциональной возможностью фильтрации
    GETdescs - получить всех потомков в виде массива ассоциативных массивов, с опциональной возможностью фильтрации

    прочие методы:
    checkoff - проверяет является ли один узел потомком другого
    addselflink - добавляет линк от узла на самого себя
    inheritlinks - линкует узел со всеми предками (родитель должен быть уже прилинкован)
    addnode - добавляет новый узел
    movenode - перемещает узел со всеми его детьми к другому родителю
    downchilds - удаляет всех потомков узла
    downbranch - удаляет сам узел и всех его потомков
    install - заполняет таблицу связей основываясь на таблице узлов выполненной ввиде таблицы смежностей

    вот с последней функцией возникли серьёзные сложности:
    PHP:
    1. <?php
    2.     function install ($rootid) {
    3.         $this->db->_table($this->linktable,array('anc'=>'int','anc'=>'int'));
    4.         $rootlink= $this->db->get0d("
    5.             select count(*)
    6.             from {$this->linktable}
    7.             where desc={$rootid}
    8.         ");
    9.         if (!$rootlink) $this->addselflink($rootid);
    10.         $descs= $this->SQLdescsets($rootid);
    11.         $this->addselflink($rootid);
    12.         while ($this->db->_numaffect()) {
    13.             $this->db->_begin();
    14.                 $this->db->query("
    15.                     insert into {$this->linktable}
    16.                     select l.anc, a.{$this->idfield}
    17.                     from {$this->listable} as a, {$this->listable} as d, {$this->linktable} as l
    18.                     where a.{$this->idfield}=d.{$this->parentfield}
    19.                     and a.{$this->parentfield} in ({$descs})
    20.                     and a.{$this->idfield} not in ({$descs})
    21.                     and l.desc= a.{$this->parentfield}
    22.                 ");
    23.                 $this->db->query("
    24.                     insert into {$this->linktable}
    25.                     select desc, desc
    26.                     from {$this->linktable}
    27.                     where desc not in (
    28.                         select anc
    29.                         from {$this->linktable}
    30.                         where anc=desc
    31.                     )
    32.                     group by desc
    33.                 ");
    34.             $this->db->_commit();
    35.         }
    36.         return true;
    37.     }
    38. ?>
    чувствую это сильно неоптимально... транзакцию приходится проводить внутри цикла, ибо при большом числе узлов скрипт так и наровит завершиться по таймауту. никого головоломки не интересуют? :)
    задача: есть таблица смежностей и пустая таблица связей. нужно организовать связи каждого узла (кроме листьев - не имеющих детей) со всеми его предками.
    сейчас у меня:
    1. добавляется линк с корня на самого себя (если его нет);
    2. ищутся узлы не засвеченные в таблице связей ("фронт"), но родители которых в таблице связей присутствуют и у которых есть хотябы 1 потомок, для каждого узла находятся идентификаторы узлов являющимися предками родителя (в том числе и сам родитель), которые линкуются с "фронтальными" узлами;
    3. добавляются линки с фронтальных узлов на самих себя (ищутся узлы, которые засвечены в таблце связей, но не входят в число узлов ссылающихся на самих себя);
    всё это повторяется, пока в таблице связей не перестанут добавляться новые узлы.

    так что, кому-нибудь интересно попробовать? если да, то могу написать драйвер под мускул...
     
  3. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    да, мускул оказался шустрее, хотя на некоторых запросах наблюдаются странные тормоза %-\
     
  4. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград