Фильтр по товарам: EAV и Sphinx

Петр Сизов

Новичок
Всем привет
Структура данных свойств по товарам у нас представлена по EAV в Mysql
productID
attributeID
attributeValue

Не совсем понятно, как реализовать такую фильтрацию на Sphinx. Например нужны продукты, которые удовлетворяют следующим критериям
attributeID=1 со значением 2 ИЛИ 3
attributeID=2 со значением 4 И 5
 

ksnk

прохожий
Примерно так же как и с остальным sql. В сфинксе он есть. https://habr.com/ru/company/sphinx/blog/61222/
Отражаем базу в сфинкс и пишем почти такой же запрос. Вопрос только - нафига? Если нужно совпадение полей - обычный mysql справится.
По моим представлениям, сфинкс это, преимущественно, удобный тестовый поиск, так что для небольшой базы было бы удобно текстовые поля товара иметь в сфинксе, а остальное в основной базе. Выковыривать подходящие по свойствам оттуда и отсюда и брать пересечение. Проблема дублирования информации о товаре в обоих базах будет не так заметна.
 

WMix

герр M:)ller
Партнер клуба
Sphinx не то чтоб база данный, а поисковой движек. там нет join, если хочется EAV в сфинксе придется денормализовать таблицу
 

Петр Сизов

Новичок
Вопрос только - нафига
Вопрос правильный - и цель поста, найти правильное решение.
Смотрите, если свойств 50 штук, и по 10 фильтрация идет, то через MYSQL - как я понимаю - надо сделать 10 INNER JOIN если данные хранятся как у нас в EAV формате или я не прав? Меня пугают эти беспонечные INNER JOIN.

денормализовать таблицу
В этом направлении и думал, что нужно данные из EAV денормализовать.
столбцы: productID attribute1 attribute2 attribute3......

В таком случае можно легко получить productID который соответствует нужному нам фильтру.
Вопрос куда денормализовать?
1 - Видел статью что в redis загоняют https://habr.com/ru/post/261137/
2 - Некоторые советуют Sphinx, преимуществ пока не понял

Какое решение Вы считаете оптимальным?
 

WMix

герр M:)ller
Партнер клуба
как я понимаю - надо сделать 10 INNER JOIN если данные хранятся как у нас в EAV формате или я не прав? Меня пугают эти беспонечные INNER JOIN.
это зря
Какое решение Вы считаете оптимальным?
все от задачи на данном этапе можно остаться в mysql
 

Петр Сизов

Новичок
Зря пугаюсь я или зря 10 INNER JOIN и надо юзать какой-то другой синтаксис?

Если думать о впринципе о денормализации - Где бы Вы рекомендовали хранить данные? В какой БД? Если речь будет идти о 200-300 колонок.
 

fixxxer

К.О.
Партнер клуба
А почему вы вообще решили, что вам нужен Sphinx?

Это задача, в которой очевидно нужен inverted index. В Sphinx, насколько я помню, inverted index на атрибуты не делается. Там, конечно, фулскан не совскем фулскан (оптимизации типа common subtree), но тем не менее, выбор fulltext-движка странен.

Нормальное решение - использовать СУБД, в которых есть поддержка inverted index. Например, в postgresql можно сложить атрибуты в jsonb-поле, создать на него GIN-индекс и искать по нему.

Есть еще забавный костыль. В innodb inverted index тоже есть, но - только для полнотекстового поиска. Если полнотекстовый поиск сам по себе не нужен, можно отключить в настройках словари и прочую лингвистику, генерировать для каждого атрибута и его значения специальное "слово", и искать по комбинации таких "слов" через full text boolean mode ;)
 

MiksIr

miksir@home:~$
Эластик в этом плане красава, конечно... например получить не просто фасеты, но сразу несколько документов из каждого фасета, и все это обмазать хитрой сортировкой и поиском по полному и не полному совпадению в одном запросе.
 

Петр Сизов

Новичок
@fixxxer я пришел с вопросом на форум, чтобы понять как правильно действовать:) Я уже понял, что Sphinx для такой задаче не совсем то, что нужно из данного поста.
Правильно я понимаю, Вы предлагаете в постгре сделать такую структуру
productID int
attributeData - поле типа JSON
В attributeData записать в формате ключ - значение.

И фильтровать в формате WHERE attributeData-> 'key' =1 AND attributeData-> 'key' =2 AND attributeData-> 'key' =3
Правильно я понял?

Единственно вопрос - такое решение будет ли быстро работать, если больше 50 аттрибутов?

Кстати, MYSQL то тоже JSON такие операции поддерживает?
Или я что-то не понимаю?
 

fixxxer

К.О.
Партнер клуба
jsonb

И фильтровать в формате WHERE attributeData-> 'key' =1 AND attributeData-> 'key' =2 AND attributeData-> 'key' =3
не, так будет фулскан. там есть специальные операторы
https://bitnine.net/blog-postgresql/postgresql-internals-jsonb-type-and-its-indexes/

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