Remitol
@Remitol
Программист Win32, Web1.0, фотограф, ретушер

Каков принцип создания фильтра в интернет-магазине, не допускающего пустой результат?

Доброго времени суток.
Имеется:
  • Интернет-магазин с базой товаров
  • Товары имеют некий набор характеристик

Задача:
  • Разработать панель фильтров по характеристикам товара, которая бы не позволяла пользователю установить комбинацию, приведшую к пустому результату.


Пока мы не сделаем запрос к БД, результат предвидеть не сможем. Исключением является, если SELECT ... FROM ... WHERE prm1=... вернет пустой результат, то и SELECT ... FROM ... WHERE prm1=... AND prm2=... AND prm3=... тоже вернет пустой результат.

Как же поступить?

В секцию WHERE запроса добавлять по одному условию пока не опустеет результат?

Сделать к БД пакет запросов со всеми возможными комбинациями WHERE? - SQL-сервер "ляжет".

Пойти от обратного? Сделать один запрос со всеми параметрами , а потом последовательно из WHERE убирать по одному и анализировать результат? Но так тоже бесполезных SELECT-ов целая кипа наберется...

Предварительно анализировать все значения параметров, фиксировать min/max и с их учетом формировать панель фильтров? Но при таком подходе задача все равно не решается полностью.
  • Вопрос задан
  • 437 просмотров
Пригласить эксперта
Ответы на вопрос 4
@chromimon
Эта задача плохо ложится на реляционную СУБД, о чем вам уже писал Сергей Горностаев
То, чем вы занимаетесь - это фасеточный поиск. Он прекрасно реализуется СУБД, умеющими т.н. полнотекстовый поиск.

Дело в том, что для реализации полнотекстового поиска используются битовые индексы, которые,помимо основной своей задачи поиска, позволяют сразу же определить и количество попавших в выборку "документов" (по терминологии: то, что называется "записями" в реляционных СУБД, то называется "документами" в движках полнотекстового поиска - такая традиция).

Вы же, используете неподходящую для этой задачи реляционную СУБД. А в реляционных СУБД определение количества записей, попавших в ответ, напротив - чрезвычайно долгая по времени операция.

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

Но в реляционных СУБД, а вы пользуйтесь именно такой, - это очень накладная операция. И делать так нельзя. Если конечно вы не хотите чтобы у вас сайт тормозил.

Одним из самых скоростных движков полнотекстового поиска являются SphinxSearch и его форк Мантикора.

ПыСы:

Почему движки полнотекстового поиска идеально подходят под реализацию фасеточного поиска.

1) Поиск по названию все равно должен быть на сайте. Движок полнотекстового поиска, в отличие от обычного движка реляционных СУБД, может искать по любой части названия, по описанию товара...

2) Как строится полнотекстовый поиск и что он из себя представляет (вне нижеописанное делает движок полнотекстового поиска, вручную этого делать не надо):

а) Фраза разбивается на отдельные слова, при этом служебные слова (предлоги, союзы, артикли и т.п.) - отбрасываются

б) Слова прогоняются через алгоритм стемминга для отсечения окончаний snowball.tartarus.org/algorithms/russian/stemmer.html

в) Полученные слова без окончаний (термы) помещаются в простейшее хранилище типа "ключ-значение", где ключём является терм. Значением является большой битовый вектор типа 00010101011110010000000011111....., где каждой позиции нуля и единицы соответствует документ (в вашем случае - товар). Для компактности используется представление RoaringBitmap roaringbitmap.org

г) С полученными битовыми векторами можно чрезвычайно быстро делать любые логические операции AND, OR, NOT

Как делается фасеточный поиск на базе полнотекстового индекса?

Очень просто, вводим искусственный терм "цвет=зеленый", строим по нему битовый вектор; вводим искусственный терм "цвет=красный", строим по нему битовый вектор; вводим искусственный терм "вид=сапог" и строим по нему битовый вектор; вводим терм "вид=ботинок" и строим по нему битовый вектор; вводим термы "размер=40", "размер=41", "размер=42", "размер=43" и строим по каждому из них битовый вектор.

После этого найти "ботинки зеленого цвета 42-го размера" - это всего лишь выполнить операцию AND по 3-м битовым векторам.

И еще раз - это все делает движок, вручную этого делать не нужно.
Ответ написан
Комментировать
sergey-gornostaev
@sergey-gornostaev Куратор тега SQL
Седой и строгий
Переложить задачу фасетного поиска на какой-нибудь движок полнотекстового поиска, более предназначенный для этого, чем РСУБД.
Ответ написан
Комментировать
alex-1917
@alex-1917
Если ответ помог, отметь решением
Любой движок взяли бы и посмотрели бы, зачем ВЕЛОСИПЕД изобретать?
Толковые фильтры есть и в опенкарт и в минишоп2 и в битрикс.
Везде они естественно платные....
Хотя про битрикс я наверное зря, это не ваше))))

Минишоп - бесплатно ставите пакет miniShop2 + mSearch2 на демо-серверах, изучаете.
На демке как раз как вам нужно - _minishop2.com/catalog/

Битрикс - бесплатно ставите демо-версию, ищите фильтр с бесплатной демо-установкой - всё! дальше неделю или сколько там даст разработчик фильтра - роетесь.

А вот опенкарт казалось бы бесплатный по сути, а фильтр просто так не поставить, только предоплата))
Ответ написан
Комментировать
Maksclub
@Maksclub
maksfedorov.ru
Выводить кроме тваоров по этому запросов еще и подходящие параметры для самих фильтров!
Вот как выглядит варианты одного параметра «Коллекция» без сортирвоки по параметру «Бренд»

5ac8a095e9a3c915151782.png



А вот как с сортировкой «Бренд»

5ac8a0b29cde3098798775.png

Итог:
Всегда в фильтрах будут поля, подходящие под другие и всегда минимум 1 товар будет
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы