MySQL и граненая навигация (фильтр по атрибутам) - PullRequest
3 голосов
/ 02 декабря 2009

Мне кажется, что этот вопрос, вероятно, задавался уже тысячу раз, поэтому я прошу прощения, если на него был дан ответ. И если так, может кто-то указать мне на правильные сообщения / ссылки?

Я пытаюсь создать многогранную навигацию для моего сайта. Он использует MySQL и вот примерный набросок таблиц, которые я использую:

products:
- id
- title
- description
attributes:
- product_id
- name
- value
categories:
- id
- name
products_to_categories:
- product_id
- category_id

То, что я хочу сделать, это отобразить список доступных атрибутов, когда вы находитесь в категории, позволяя вам выбрать одно или несколько значений для каждого из этих атрибутов. Чтобы дать вам пример, посмотрите на эту страницу из Office Depot: http://www.officedepot.com/a/browse/binders/N=5+2177/

До сих пор я использовал много объединений для фильтрации по нескольким атрибутам:

SELECT products.*, a_options.*
FROM products_to_categories AS pc, products,
attributes AS a_options,    /* list of attribute/value pairs I can continue to refine on */
attributes AS a_select1     /* first selected attribute */
attributes AS a_select2     /* second selected attribute */
...
WHERE pc.category_id = 1
AND products.id = pc.product_id
AND a_options.product_id = products.id
AND a_options.name != 'Color' AND a_options.name != 'Size'
AND a_select1.product_id = products.id
AND a_select1.name = 'Color' AND (a_select1.value = 'Blue' OR a_select1.value = 'Black')
AND a_select2.product_id = products.id
AND a_select2.name = 'Size' AND a_select2.value = '8.5 x 11'

В основном a_options вернет все атрибуты для тех продуктов, которые являются подмножеством фильтров, которые я применил, используя a_select1 и a_select2. Поэтому, если я использую пример Binders из Office Depot, я хочу показать все доступные атрибуты после выбора синего или черного цвета для цвета и «8,5 x 11» для размера.

Затем я использую код PHP, чтобы удалить дубликаты и расположить полученные атрибуты в массив, например:

attributes[name1] = (val1, val2, val3, ...)
attributes[name2] = (val1, val2, val3, ...)

Есть ли способ ускорить мой запрос или написать его более эффективно? У меня есть настройки индексов по имени и значению в таблице атрибутов (а также по всем идентификационным номерам). Но если кто-то выберет пару атрибутов, запрос будет выполняться медленно.

Заранее спасибо за помощь,
Шридхар

Ответы [ 2 ]

7 голосов
/ 02 декабря 2009

«Затем я использую PHP-код для удаления дубликатов»

Тогда оно не будет масштабироваться.

После того, как я прочитал http://www.amazon.com/Data-Warehouse-Toolkit-Techniques-Dimensional/dp/0471153370 Я без остановки катал грани и механизмы фильтрации.

Основная идея заключается в том, что вы используете схему типа "звезда".

Вы создаете таблицу фактов, в которой хранятся факты

customerid | dateregisteredid | datelastloginid
1 | 1 | 1
2 | 1 | 2

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

date_registered
Id | weekday | weeknumber | year | month | month_year | daymonth | daymonthyear
1 | Wed      | 2            | 2009 | 2   |2-2009      | 4        | 4-2-2009

Затем, какую бы дату "парадигмы" вы не использовали, возьмите все идентификаторы из этой таблицы измерений и

 select * from the fact table where the fact.dateregisteredid is IN( ... the ids from the date dimension table that represent your time period)

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

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

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

Существуют более эффективные способы использования коммерческих баз данных, таких как Oracle, но звездообразная схема делает их доступными для всех, кто имеет реляционную базу данных с открытым исходным кодом и какое-то время.

Вы обязательно должны прочитать инструментарий, но он обсуждает много вещей, которые могут сэкономить вам значительное время. Подобные стратегии для работы с обновленными данными и сохранения истории аудита в приложении отчетности. Для каждой проблемы он выделяет несколько решений, каждое из которых применимо в разных контекстах.

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

4 голосов
/ 28 января 2014

Вы можете сгенерировать таблицу фасетов на основе ваших нормализованных таблиц базы данных.
Например:

> SELECT * FROM product_facet
product_id | facet_type | facet_value
1          | color      | blue
2          | color      | blue
3          | color      | green
4          | color      | yellow
1          | speed      | slow
2          | speed      | slow

Затем просто выполните этот запрос, чтобы получить общее количество по атрибуту:

SELECT facet_type, facet_value, COUNT(facet_value) as total
FROM product_facet
GROUP BY facet_type, facet_value;

Результат:

facet_type | facet_value | total
color      | blue        | 2
color      | green       | 1
color      | yellow      | 1
speed      | slow        | 2

При поиске по критериям вы можете выбрать таблицу фасетов по идентификатору продукта:

SELECT facet_type, facet_value, COUNT(facet_value) as total
FROM product_facet
WHERE product_id in (SELECT product_id FROM products WHERE ... )
GROUP BY facet_type, facet_value;
...