ФорумРазработкаБазы данных → Принцип работы nested sets

Принцип работы nested sets

  • TRIAL

    Сообщения: 988 Репутация: N Группа: Джедаи

    Spritz 12 сентября 2012 г. 5:54

    Решил ради интереса посмотреть принцип работы сия чуда. С виду всё красиво хотя и замудрено до жути.
    Но вот возник у меня один вопрос. Как получить все данные именно выбранного раздела?
    Допустим у нас есть дерево такого вида:
    a - b - c (основной раздел - подраздел - под-подраздел)
    d - b - c (второе древо и т.д.)
    В итоге в адресной строке будем иметь следующее:
    mysite.ru/a/b/c/ и mysite.ru/d/b/c/
    Как извлечь из таблицы данные нужные нам, ведь фактически имя раздела и подраздела одинаковые, разные у них только корневые разделы. Неужели придется идти от начала древа и до конца? Но тогда теряется весь смысл этого самого nested sets. Объясните пожалуйста где я туплю и чего я не понимаю?
    А конечная задача сделать возможность добавлять бесконечное множество вложений и чтоб имена этих самых вложений могли совпадать. Ведь по большому счету можно сделать ссылку типа mysite.ru/a/a/a/a/a/a/a/a/… И вот как в такой схеме вычислять конкретный элемент?

    PS. Надеюсь мысль мою вы поняли :) Если нет, то спрашивайте, я объясню подробнее :)
    from TRIAL with LOVE
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 12 сентября 2012 г. 6:40, спустя 46 минут 20 секунд

    И вот как в такой схеме вычислять конкретный элемент?

    а зачем тебе конкретный?

    последний крайний да и все.

    а от него уже получить и корневые и детей
    Сапожник без сапог
  • TRIAL

    Сообщения: 988 Репутация: N Группа: Джедаи

    Spritz 12 сентября 2012 г. 6:49, спустя 8 минут 27 секунд

    Ну это же одним запросом к БД не обойдется или я не прав? У меня щас все строится по схеме id, sub_id, соответственно всё дерево рисуется рекурсивной функцией и уж сколько там запросов к БД идет не знаю, но явно не мало, пускай и происходит это всё без единой задержки. Я то искал способ чтобы обращаться к БД всего 1 раз и получать все данные.
    Пока на обед ходил, мысль пришла при первой загрузке сайта создавать массив из всех эл-тов дерева и записывать всё это в сессию чтобы в дальнейшем только к ней обращаться. Наверное должно это выглядеть как-то так $_SESSION['site_tree'][a][a][a][a][a][a] или как-то так. В общем чертить путь внутри многомерного массива чтоб в конечном итоге получить id нужного нам раздела.
    Не знаю на сколько эта идея нормальна правда… )))
    from TRIAL with LOVE
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 12 сентября 2012 г. 6:59, спустя 9 минут 54 секунды

    храни в Closure Tree
  • TRIAL

    Сообщения: 988 Репутация: N Группа: Джедаи

    Spritz 12 сентября 2012 г. 7:15, спустя 16 минут 37 секунд

    Думал и такое сделать но чет не очень привлекает.
    Если имя раздела изменится, нужно будет по всей базе проходится и заменять данные. Тоже не айс. Всё еще склоняюсь к древу в сесии. Хотя вот народ пишет что не самое хорошее решение разный мусор в сессии хранить. Думал может какой кэш использовать или еще чего, но никогда с таким дел не имел.
    from TRIAL with LOVE
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 12 сентября 2012 г. 7:21, спустя 5 минут 35 секунд

    нет, если имя меняется - по всей базе не нужно бегать. Только если родитель, и то не совсем по всей
    Спустя 227 сек.
    и ваще у меня вот доктрина2 с соответствующим плагином. Она сама занимается поддержкой структуры данных
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 12 сентября 2012 г. 8:27, спустя 1 час 6 минут 31 секунду


    нет, если имя меняется - по всей базе не нужно бегать. Только если родитель, и то не совсем по всей
    Спустя 227 сек.
    и ваще у меня вот доктрина2 с соответствующим плагином. Она сама занимается поддержкой структуры данных
    а у нас в квартире газ
    Спустя 4 сек.
    если вы знаете что это такое :D:D:D
    Сапожник без сапог
  • Josh

    Сообщения: 2008 Репутация: N Группа: Кто попало

    Spritz 12 сентября 2012 г. 9:31, спустя 1 час 3 минуты 20 секунд

    Пишу сейчас цмс. Сам вожусь с nested sets:

    Решил ради интереса посмотреть принцип работы сия чуда. С виду всё красиво хотя и замудрено до жути.
    Но вот возник у меня один вопрос. Как получить все данные именно выбранного раздела?
    Допустим у нас есть дерево такого вида:
    a - b - c (основной раздел - подраздел - под-подраздел)
    d - b - c (второе древо и т.д.)
    В итоге в адресной строке будем иметь следующее:
    mysite.ru/a/b/c/ и mysite.ru/d/b/c/
    Как извлечь из таблицы данные нужные нам, ведь фактически имя раздела и подраздела одинаковые, разные у них только корневые разделы. Неужели придется идти от начала древа и до конца? Но тогда теряется весь смысл этого самого nested sets. Объясните пожалуйста где я туплю и чего я не понимаю?
    А конечная задача сделать возможность добавлять бесконечное множество вложений и чтоб имена этих самых вложений могли совпадать. Ведь по большому счету можно сделать ссылку типа mysite.ru/a/a/a/a/a/a/a/a/… И вот как в такой схеме вычислять конкретный элемент?

    PS. Надеюсь мысль мою вы поняли :) Если нет, то спрашивайте, я объясню подробнее :)
    Почему не a-b-c и d-e-f и site.ru/a, site.ru/b, site.ru/c, site.ru/d, site.ru/e, site.ru/f ? 1 запрос и все хлебные крошки в нём

    нет, если имя меняется - по всей базе не нужно бегать. Только если родитель, и то не совсем по всей
    Спустя 227 сек.
    и ваще у меня вот доктрина2 с соответствующим плагином. Она сама занимается поддержкой структуры данных
    Ой да ну - ты постоянно про неё говоришь, как будто бы доктрина = панацея. Не только она умеет работать с деревьями official&client=firefox-a">https://www.google.com.ua/search?q=php+nested+sets+class&ie=utf-8&oe=utf-8&aq=t&rls=org.mozillaruofficial&client=firefox-a
  • Абырвалг

    Сообщения: 6476 Репутация: N Группа: Джедаи

    Spritz 12 сентября 2012 г. 9:38, спустя 7 минут 26 секунд

    вообще если для контента - то phpcr с разными бекендами http://phpcr.github.com/
  • TRIAL

    Сообщения: 988 Репутация: N Группа: Джедаи

    Spritz 14 сентября 2012 г. 7:22, спустя 1 день 21 час 43 минуты

    В общем что получилось в конечном итоге:
    Структура БД
    +—————+———————–+——+——–+—————+———————-+
    | Field | Type | Null | Key  | Default  | Extra |
    +—————+———————–+——+——–+—————+———————-+
    | id | int(10) unsigned | NO | PRI  | NULL  | auto_increment |
    | name | varchar(30) | YES |  | NULL  | |
    | sub | int(11) | YES |  | 0  | |
    | vname | varchar(30) | YES |  | NULL  | |
    +—————+———————–+——+——–+—————+———————-+

    Скрипт:
    // URL
    $a = array();
    $n = 0;

    // Создаем массив с древом сайта
    $res = mysql_query("SELECT `id`, `sub`, `name`, `vname` FROM `main_table` ORDER BY `number`, `id`");

    while($row = mysql_fetch_assoc($res)) {

    if(empty($a[$row['sub']]))
    $a[$row['sub']]=array();

    $a[$row['sub']][]=$row;
    }

    // Разбивка url'а

    $url_arr = explode("/", $_GET['dir']);

    // Проверяем есть ли доп. параметры в последнем элементе массива (пример: /?id=xxx&atr=abc)
    if(substr($url_arr[count($url_arr)-1], 0, 1) == "?") {

    $tmp_arr_ext = substr($url_arr[count($url_arr)-1], 1);

    $tmp_arr_ext = explode("&", $tmp_arr_ext);

    foreach($tmp_arr_ext as $k => $v) {

    $a = explode("=", $v);

    $url_arr_ext[$a[0]] = $a[1];
    }
    }

    //
    $dir = array_slice($url_arr, 0, -1);

    $c_dir = count($dir);


    // Функция определения текущего id страницы
    function tree_id_search(&$a,$sub=0,$count=0) {

    if(empty($a[$sub])) return;

    global $dir, $c_dir, $n, $cur_dir_id; // уровень вложения
    $msr = count($a[$sub]);

    // Если есть вложение
    if($sub != 0) {

    $n++;

    for($i=0;$i<$msr;$i++) {

    if($a[$sub][$i]['name'] == $dir[$n] && $n == ($c_dir-1)) { $cur_dir_id = $a[$sub][$i]['id']; break; }

    tree_id_search($a,$a[$sub][$i]['id'],$msr);
    }
    $n–;
    }
    else {

    $n = 0;

    for($i=0;$i<count($a[$sub]);$i++) {

    tree_id_search($a,$a[$sub][$i]['id'],$msr);
    }
    }
    }

    // Вычисляем ID текущего раздела
    tree_id_search($a);


    Ну вот как-то так.
    По хорошему осталось еще оптимизировать функцию.
    Как итог - имеем всего 1 запрос к БД. Причем если занести массив древа сайта в сессию, то сокращаем обращение к базе за поиском id раздела до одного (при первом заходе) на всё время лазания по сайту.

    PS. Конечно вариант не идеальный, но посмотрим как покажет себя в будущих проектах.
    from TRIAL with LOVE
  • Josh

    Сообщения: 2008 Репутация: N Группа: Кто попало

    Spritz 14 сентября 2012 г. 7:44, спустя 21 минуту 51 секунду

    TRIAL, Просто блять охуетительно, а сайт рости не будет? а если 10000 страничек будет?
  • TRIAL

    Сообщения: 988 Репутация: N Группа: Джедаи

    Spritz 14 сентября 2012 г. 7:51, спустя 7 минут 38 секунд

    Ну смотря что страницами считать. Если есть лента новостная и там 10 000 новостей по то сути страница то одна в которую передаешь какой-нибудь news_id. Хотя если реально страниц будет столько, моя схема не то что загнется, но будет работать весьма долго.
    Я же не говорю что вариант идеальный. Хотя не пойму чем тот же nested sets лучше будет. Тут конечно всё от глубины вложения зависит. Навряд ли она будет больше 5-10, тогда проще реально сделать несколько запросов в базу чем прогонять каждый раз весь массив в поисках нужного ключа. В общем буду думать дальше и искать золотую середину.
    from TRIAL with LOVE
  • TRIAL

    Сообщения: 988 Репутация: N Группа: Джедаи

    Spritz 14 сентября 2012 г. 8:00, спустя 9 минут

    Что-то совсем не хочется мне url'ы в базу вносить. Не знаю почему конечно, но как-то чем-то смущает. С другой стороны конечно это резко упрощает всю работу и реально не надо заниматься таким онанизмом как у меня. Пожалуй я всё таки рассмотрю твой вариант.
    from TRIAL with LOVE
  • Josh

    Сообщения: 2008 Репутация: N Группа: Кто попало

    Spritz 14 сентября 2012 г. 8:59, спустя 58 минут 36 секунд


    Ну смотря что страницами считать. Если есть лента новостная и там 10 000 новостей по то сути страница то одна в которую передаешь какой-нибудь news_id. Хотя если реально страниц будет столько, моя схема не то что загнется, но будет работать весьма долго.
    Я же не говорю что вариант идеальный. Хотя не пойму чем тот же nested sets лучше будет. Тут конечно всё от глубины вложения зависит. Навряд ли она будет больше 5-10, тогда проще реально сделать несколько запросов в базу чем прогонять каждый раз весь массив в поисках нужного ключа. В общем буду думать дальше и искать золотую середину.
    Глубина вложения ни о чём не говорит, если она будет 5 то в ширину может быть 10000, если понял о чём я. А вообще в чём проблемы то у тебя с нестед сетс? 1 запрос делает всё
  • Josh

    Сообщения: 2008 Репутация: N Группа: Кто попало

    Spritz 14 сентября 2012 г. 9:58, спустя 59 минут 36 секунд

    некашерно выглядит
    то есть по твоему кашерно, Абрам

Пожалуйста, авторизуйтесь, чтобы написать комментарий!