LINUX.ORG.RU

как правильно хранить в БД категории и подкатегории продуктов с почти неограниченной вложенностью?


0

1

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

То есть, возможны любые варианты вложенности.

  • продукты-->кислые-->яблоко_зелёное;
  • продукты-->фрукты-->яблоко_зелёное;
  • продукты-->не_овощи-->фрукты-->яблоко_зелёное;
  • продукты-->фрукты-->яблоки_переростки-->яблоко_большое_жёлтое;
  • яблоко_не_настоящее; - не входит ни в одну категорию.

Самые частые операции с данным хранилищем:

  • получить список всех продуктов в такой-то категории;
  • получить список всех категорий, в которые входит данный продукт.

Думается, что подобные задачи возникают регулярно, однако кроме таблички со списком отношений «старшая_категория--входящая_в_неё_категория» ничего в голову не приходит. Подобная же табличка заставляет строить рекурсивные запросы, что крайне негативно сказывается на процессорном времени, если уровень вложенности начинает превышать три-четыре шага.

Как правильно решать такую задачу?

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

anonymous
()
Ответ на: комментарий от KDE41user

> Nested set

Я думал, оно применимо только для случаев «нормального» дерева, где у каждого листка всего один путь до корня. Здесь же зелёное яблоко состоит одновременно в продуктах, фруктах, кислых и не_овощах. И как мне тут явно задать соседей слева и справа, я не догоняю. Я чего-то не понимаю?

monsterkiller
() автор топика
Ответ на: комментарий от anonymous

Предлагаете забить на присутствие рекурсии, пусть остаётся, и лучше не сделать?

monsterkiller
() автор топика
Ответ на: комментарий от monsterkiller

>Я думал, оно применимо только для случаев «нормального» дерева

Да, это я невнимательно прочел топик.

KDE41user
()
Ответ на: комментарий от monsterkiller

Я не знаю как ещё сделать в табличных БД такую структуру, кроме 2 таблиц:
1) сами объекты-категории
2) связи между объектами (ссылка на верхний объект и на нижний объект)

anonymous
()
Ответ на: комментарий от guyvernk

Ну почему. Например, в Оракле поиск в таких структурах легко делается через select ... connect by, с помощью которого можно легко пробежаться вверх и вниз.

anonymous
()
Ответ на: комментарий от anonymous

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

guyvernk
()
Ответ на: комментарий от guyvernk

А теперь самая жесть: мне надо будет получать эти списки внутри транзакций в постгресе. Не просто транзакций, но и чистых процедур, дёргаемых из приложения одним селектом.

Можно ли безболезненно натянуть графоориентированную NoSQL-базу поверх постгреса? :) Или остаётся только надеяться на кэш?

monsterkiller
() автор топика

Мне кажется сам подход неверен. Вы свалили всё в кучу и теперь ломаете голову как достать предмет со дна заваленный другими предметами. Думаю надо отталкиваться от действий с предметами. скажем так:

продукты->на продажу  - фрукты (таблица с категориями - кислое, зелёное)
                    \ - овощи (таблица с категориями - кислые, зелёные)
продукты->на витрину(таблица с категориями - пластмассовое)

ну или подобное в зависимости от задачи которые преследуются.

Deleted
()
Ответ на: комментарий от Deleted

Ну зачем такие сложности с особыми базами данных? Тот же Оракл такие структуры данных жрёт без вопросов и никаких проблем нет в работе с ними.

anonymous
()
Ответ на: комментарий от anonymous

хорошо если так, я честно говоря даже не представляю как подобную структуру переложить на реляционную БД. Может приведёте коротенький пример? Мне будет интересно посмотреть подход

Deleted
()
Ответ на: комментарий от anonymous

Мне кажется не выйдет. Вы смешиваете объекты и категории в одну кучу, между тем тут даны отдельно объекты (фрукты) и отдельно категории (кислые)

Deleted
()
Ответ на: комментарий от Deleted

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

1) узлы-посредники nodes (ИД, ссылка на объект№1, ссылка на объект №2, ....., ссылка на объект №100)

2) связи links (ссылка на узел вверху, ссылка на узел внизу)

задача (для Оракла): выбрать все автомашины и яблоки, входящие в объект «цвет» с типом «желтый»

select nodes.auto_id, nodes.apple_id from links, nodes 
where nodes.id = links.low_id and (nodes.auto_id is not NULL or nodes.apple_id is not NULL) 
connect by prior links.low_id = links.high_id
start with links.high_id in 
(select ID from nodes, colors where colors.type='yellow' and nodes.color_id = colors.id)
anonymous
()

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

amomymous ★★★
()
Ответ на: комментарий от monsterkiller

> А теперь самая жесть: мне надо будет получать эти списки внутри транзакций в постгресе.

Для постгреса есть сторонний костыль, умеющий connect by. Если нагрузка на БД небольшая, то пойдёт. Не знаю только, поддерживается ли он для последних версий pg.

SOmni ★★
()
Ответ на: комментарий от amomymous

> Сделайте денормализацию и храните в продукте все категории и подкатегории, в которые он входит. При изменениях категорий и принадлежности подкатегорий к категориям, перестраивайте (обновляйте) все эти поля в таблице продуктов (ну как это обычно делается). Получается вполне эффективно, хотя кодить придется чуть больше.

К этому пока и склонился, спасибо.

А варианты с connect by выглядят на первый взгляд какими-то слишком заморочными.

monsterkiller
() автор топика

Две указанные операции никак не используют иерархию категорий. Думается мне, что можно на неё вообще забить. А тогда получается тривиально.

Miguel ★★★★★
()
Ответ на: комментарий от Xellos

Вряд ли. ЕМНИП, в своё время разработчики PG сказали, что такое счастье им нафиг не надо, что весьма огорчило человека, разрабатывающего патч. С тех пор не слежу.

SOmni ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.