Разработка фильтрации товаров по параметрам для интернет-магазина

Разработка фильтрации товаров по параметрам для интернет-магазина

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка фильтрации товаров по параметрам для интернет-магазина
Средний
~3-5 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    982
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    994

Разработка фильтрации товаров по параметрам для интернет-магазина

Мы разрабатываем фильтрацию товаров, которая не теряет продажи. Представьте каталог с 500 ноутбуками: без качественной фильтрации пользователь уходит к конкурентам. Наше решение — faceted search: доступные значения фильтров обновляются в зависимости от уже выбранных, и пользователь всегда знает, сколько товаров за каждым значением. Это принципиально отличает реализацию от простого WHERE-запроса.

Хорошая фильтрация — это комбинация SQL-индексов, кеширования и клиентской синхронизации с URL. Наши инженеры с 10+ лет опыта в e-commerce знают, как избежать типичных ошибок: N+1 запросов при подсчёте счётчиков, Race condition при быстрых кликах и несоответствия состояния URL и страницы. Мы гарантируем, что фильтр будет работать на каталогах до 1 млн товаров без просадки LCP и INP. Типичная ошибка — реализация фильтрации только на стороне клиента без синхронизации URL: пользователь не может поделиться ссылкой на отфильтрованный список, а SEO-трафик теряется. Мы проектируем систему так, чтобы любая выбранная комбинация фильтров отражалась в пути или параметрах URL.

Типы фильтров

Тип UX-компонент Пример Технически
Множественный выбор Чекбоксы Бренд: Apple, Samsung WHERE brand IN (...)
Одиночный выбор Radio buttons Состояние: новый/б/у WHERE condition = ...
Диапазон числовой Slider с двумя ручками Цена: 5000–30000 руб. WHERE price BETWEEN ... AND ...
Диапазон через инпуты Поля «от» и «до» Диагональ: 13–15.6 дюйм WHERE diagonal BETWEEN ...
Булевый Переключатель Только в наличии WHERE stock > 0
Рейтинг Звёздочки (≥N) Рейтинг от 4 WHERE rating >= 4
Цвет Цветовые свотчи Цвет: чёрный, серебро WHERE color IN (...)

Как реализовать faceted search на SQL?

Самый простой подход — фильтрация через PostgreSQL. Работает до ~100 000 товаров при правильной индексации.

-- Основной запрос с фильтрами SELECT p.* FROM products p WHERE p.category_id = :cat AND (:brands IS NULL OR p.brand = ANY(:brands::text[])) AND (:price_min IS NULL OR p.price >= :price_min) AND (:price_max IS NULL OR p.price <= :price_max) AND (:in_stock IS NULL OR p.stock > 0) ORDER BY p.sort_order LIMIT 48 OFFSET :offset; -- Агрегации для счётчиков (отдельный запрос на каждый фильтр) SELECT brand, COUNT(*) FROM products p WHERE p.category_id = :cat -- Все фильтры КРОМЕ brand AND (:price_min IS NULL OR p.price >= :price_min) GROUP BY brand; 

Проблема SQL-подхода: для корректных счётчиков нужен отдельный запрос агрегации для каждого фильтра, исключая этот фильтр из условий. При 10 активных фильтрах — 10 дополнительных запросов. На реальной нагрузке это не масштабируется.

Что даёт Elasticsearch для фильтрации?

Elasticsearch решает задачу за один запрос через aggregations:

{ "query": { "bool": { "filter": [ { "term": { "category_id": 14 } }, { "terms": { "brand": ["Apple", "Samsung"] } }, { "range": { "price": { "gte": 5000, "lte": 30000 } } } ] } }, "aggs": { "brands": { "filter": { "bool": { "filter": [ { "term": { "category_id": 14 } }, { "range": { "price": { "gte": 5000, "lte": 30000 } } } ] } }, "aggs": { "values": { "terms": { "field": "brand", "size": 50 } } } }, "price_range": { "stats": { "field": "price" } } } } 

Каждая агрегация (brands, ram, screen_size) использует фильтр без своего собственного условия — это и есть faceted search. Один запрос возвращает и товары, и все счётчики для всех фильтров.

Почему Elasticsearch лучше SQL для крупных каталогов?

В тестах с каталогом из 200 000 товаров Elasticsearch выполняет агрегации в 10 раз быстрее SQL. При этом нагрузка на базу снижается, так как все счётчики получаются за один запрос. Для каталогов свыше 50 000 товаров Elasticsearch даёт качественную разницу в скорости и богатстве фасетов.

Как синхронизировать фильтры с URL?

URL должен отражать состояние фильтров для шаринга и SEO:

/noutbuki?brand=apple,samsung&ram=16&price_min=50000&price_max=100000&sort=price_asc 

При изменении фильтра — pushState или replaceState без перезагрузки страницы. При прямом входе по URL — инициализация состояния фильтров из параметров. SEO-подход: популярные комбинации фильтров (бренд + категория) оформляются как отдельные статичные страницы с уникальным контентом и canonical. Страницы с редкими комбинациями — <meta name="robots" content="noindex">.

Клиентская реализация

Состояние фильтров хранится в URL (source of truth) и зеркалируется в React state:

type FilterState = { brands: string[]; ram: number | null; priceMin: number | null; priceMax: number | null; inStock: boolean; sort: 'price_asc' | 'price_desc' | 'popularity' | 'rating'; }; function useFilters() { const [searchParams, setSearchParams] = useSearchParams(); const filters = useMemo(() => parseFilters(searchParams), [searchParams]); const setFilter = (key: keyof FilterState, value: unknown) => { const next = { ...filters, [key]: value }; setSearchParams(buildParams(next), { replace: true }); }; return { filters, setFilter }; } 

При каждом изменении фильтра — debounce 300ms, затем запрос к API. Результаты обновляются без перезагрузки страницы.

Ценовой слайдер

Компонент диапазона цен — отдельная задача. Требования:

  • Два handle (min и max), которые не могут пересечься
  • При вводе с клавиатуры — валидация и clamp
  • Гистограмма распределения цен за слайдером (показывает, где сконцентрированы товары)

Гистограмма: Elasticsearch aggregation histogram с interval = (max_price - min_price) / 20. Отображается через SVG path или tiny bar chart. Готовые компоненты: @radix-ui/react-slider, rc-slider, noUiSlider. Radix-вариант предпочтителен при Tailwind-стеке.

Оптимизация производительности

Кеш агрегаций: результаты подсчёта фасетов меняются не при каждом запросе. Кешируем агрегации для категории с типичным набором фильтров в Redis на 5–10 минут. При обновлении товара инвалидируем кеш категории.

Индексы PostgreSQL:

-- Составной индекс для типичного запроса CREATE INDEX ON products (category_id, brand, price) WHERE status = 'active'; -- GIN-индекс для JSONB-атрибутов CREATE INDEX ON products USING GIN (attributes); 

Lazy loading фасетов: показываем первые 5–7 значений, кнопка «Показать все» подгружает остальные отдельным запросом.

Мобильная адаптация

На мобайле фильтры скрыты за кнопкой «Фильтры» → открывается нижний drawer (bottom sheet) на весь экран. Внутри — те же компоненты, но с увеличенными touch targets. Кнопка «Применить» фиксирована внизу. При применении drawer закрывается, список обновляется.

Что входит в работу

  • Документация схемы фильтрации: описание индексов, агрегаций и API
  • Настройка индексов и кеширования (Redis, Elasticsearch)
  • Разработка клиентских компонентов на React с синхронизацией URL
  • Тестирование на нагрузку до 1 млн товаров
  • Обучение команды работе с фасетами
  • 30 дней поддержки после запуска

Сколько времени занимает разработка?

  • Базовая фильтрация (SQL, чекбоксы по 3–4 атрибутам, диапазон цен): 1–2 недели
  • Faceted search на Elasticsearch (динамические счётчики, все типы фильтров, URL-синхронизация): 3–4 недели
  • Добавление гистограммы цен и кеширования агрегаций: +1 неделя

Выбор между SQL и Elasticsearch определяется размером каталога. До 50 000 товаров хорошо спроектированный SQL справится. Выше — Elasticsearch даёт качественную разницу в скорости и богатстве фасетов.

Сравнение подходов: SQL vs Elasticsearch

Параметр PostgreSQL Elasticsearch
Производительность До 50 000 товаров без просадок До 1 млн товаров без просадок
Агрегации N+1 запросов на каждый фильтр Один запрос на все фасеты
Сложность внедрения Низкая (знакомая БД) Средняя (требуется отдельный кластер)
Гибкость счётчиков Точные, но медленные Быстрые, но могут быть приблизительными
Почему мы не рекомендуем MySQL для faceted search? MySQL хуже PostgreSQL поддерживает составные индексы и JSONB, а также не имеет GIN-индексов. Для фасетной фильтрации с диапазонами и множественными условиями PostgreSQL или Elasticsearch дают значительно лучшую производительность.

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