[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Выбор максимально совпадающего товара
Страницы: 1, 2
vagrand
В общем задачка довольно распространенная, но чего-то так с наскока ничего толкового в голову не приходит.
В общем, есть каталог товаров. Все товары прикреплены к нескольким категориям. Связка храниться в отдельной таблице в виде пары столбцов: item_id, category_id. Тут все довольно стандартно. Но вот хочется на странице просмотра товара вывести "похожие" и таким образом, чтобы отсортировать их по максимальному числу совпадающих категорий.
Вот чего-то в голову не приходит простого и быстрого метода. Полагаю что нужно думать в сторону отдельной таблицы со сгруппированными данными, но вот какой она должна быть, пока не придумал.
У кого будут какие мысли?

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
FatCat
Я бы сделал "в лоб": добавил в таблицу товаров текстовое поле, и в нем через запятую список категорий этого товара.

_____________
Бесплатному сыру в дырки не заглядывают...
vagrand
И что, как ты видишь выборку?

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
FatCat
Смотря какие критерии "похожести".
Если полное совпадение списка категорий - простой LIKE.
Если не полное совпадение, остается возможность LIKE '%,999,%'
Понятно, что список категорий писать в базу как
$catz = ",".implode(",",$categories).",";


_____________
Бесплатному сыру в дырки не заглядывают...
vagrand
FatCat
Цитата
Смотря какие критерии "похожести".


Я же написал какие критерии. Полностью могут не совпадать, но хочется чтобы вначале были максимально похожие. А с лайком не прокатит.
Вот например у меня есть товар с категориями "1,2,3,4,5" и есть товар с категориями "2,3,4" то тут like не прокатит совсем.

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
waldicom
На поверхности лежит вариант с чем-то типа array_intersect()
Но в базу данных, понятно, такое не засунешь. Может сделать рассчет статическим и пересчитывать при изменении/добавлении/удалении категорий?

_____________
Свои мозги еще никто не отменял.
Телепатов нету.
FatCat
Цитата (vagrand @ 29.09.2014 - 21:57)
есть товар с категориями "1,2,3,4,5" и есть товар с категориями "2,3,4" то тут like не прокатит совсем.

WHERE cat_id LIKE '%,2,%' OR  cat_id LIKE '%,3,%' OR  cat_id LIKE '%,4,%'


_____________
Бесплатному сыру в дырки не заглядывают...
vagrand
FatCat
Ну во-первых это ересь и хотелось бы быстрый запрос, а во-вторых, это не сработает. Проблема ведь не в выборке списка похожих. Это я могу и при существующей структуре сделать. Проблема в том, как выбранные отсортировать по максимальному совпадению.

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

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
rooor
FatCat
да не... костыль, который не будет работать, если, например, 4 категория будет последней в строке, то в таком виде LIKE '%,4,%' она не найдётся, т.к. запятой после неё нет

как вариант - отдельная таблица с параметрами товаров, выбирать по COUNT, где больше - значит наиболее похожий товар, только хз как))
vagrand
В общем нашел сам более-менее приемлемый вариант:


select g.id, g.alias, count(r.id) as rate
from goods g
inner join goods_categories_relations r on g.id = r.goods_id
where r.category_id in (2,13,15,16,9)
group by g.id
order by rate desc


Думаю особо объяснять смысла нет. Естественно сортировка без индексов, но пока ничего лучшего в голову не приходит.

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
AllesKlar
vagrand
Есть идея, но нужно допилить.
Немного денормализуй таблицу товаров, к каждому товару добавь поле, которое будет хранить некое значение, назовем его "вес категорий" (integer). При добавлении / удалении / изменении товров/категорй, данное значение должно пересчитаться. Для одиаковых наборов чисел (1,2,3 и 3,1,2) вес должен быть один. Чем меньше различие в двух наборах чисел, тем бдиже друг к другу значения веса.
Далее просто, берем вес категорий товара и запрашиваем 5-10 следующих / предыдущих значений по таблице.

Осталось придумать алгоритм расчета веса категорий smile.gif
Кто заморочится, тот тру smile.gif

_____________
[продано копирайтерам]
vagrand
AllesKlar
Я изначально тоже думал в эту сторону, но такой алгоритм расчета веса мне не по плечу. Да и замутно очень все выходит. Еще и пересчеты эти не нравятся. Уж легче просто юзать тот запрос, что я придумал и кэшить результат. А очищать его можно когда редактируется привязка любого товара к категориям, что происходит не часто.

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
sergeiss
Цитата (vagrand @ 29.09.2014 - 23:19)
В общем нашел сам более-менее приемлемый вариант: ...

Мне кажется, это самый правильный вариант.

Цитата (vagrand @ 29.09.2014 - 23:19)
Естественно сортировка без индексов, но пока ничего лучшего в голову не приходит.

У тебя сколько предполагается данных в таком запросе? Если 2-3-4 сотни, то отсутствие индексов не критично. Если тысячи, то тогда, возможно, быстрее будет сделать сортировку в ПХП - хотя это надо проверять.

При большом количестве выбранных данных можно попробовать (оценить по скорости) такой вариант.
1. Делаешь свою выборку, но без сортировки. Данные пишешь в некую временную таблицу, которую тут же в запросе и создаешь (CREATE TABLE ... SELECT ...). Имя временной таблицы, естественно, должно быть уникальным.
2. Создаешь индекс для этой таблицы.
3. Выбираешь данные из нее в нужном порядке.
4. Удаляешь временную таблицу.
Несмотря на "многоходовость", такой вариант при некоторых условиях может оказаться быстрее, чем просто сортировать большую (много тысяч или десятков тысяч записей) выборку, не имеющую индекса.

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

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
vagrand
sergeiss
В принципе особо большого количества товаров при такой выборке у меня не предполагается + буду использовать кэш, так что думаю мутить что-то со временными таблицами смысла особого нету. Но все равно за обсуждение всем спасибо.

_____________
Senior PHP developer: PHP5, MySQL, JavaScript, CakePHP, Yii/Yii2, Zend Framework, Smarty, XML/Xslt, JQuery, Jquery Mobile, Bootstrap, ExtJS, HTML, HTML5, CSS, Linux, SVN, Git, Memcached, Redis, MongoDB, Zend Guard, Ioncube, FFMpeg, PayPal, Webmoney, Qiwi, Facebook API, Vkontakte Api, Google API, Twitter Api, Steam Api.
Junior Android Developer: Android SDK, многопоточность, работа с HTTP запросами, JSON, SQLite, фрагменты.
sergeiss
Цитата (vagrand @ 30.09.2014 - 10:25)
В принципе особо большого количества товаров при такой выборке у меня не предполагается + буду использовать кэш, так что думаю мутить что-то со временными таблицами смысла особого нету.

Как раз есть smile.gif Только тогда не совсем так, как я описал. Но - почти так. Из описанного мной алгоритма удаляешь п.4. В п.1 имя таблицы должно быть не уникальным, а определенным. И получаешь ты тот самый кэш, в виде обычной таблицы. Которая периодически обновляется (пересоздается), когда что-то меняется в данных.
Плюс в том, что не надо ничего придумывать, всё уже есть в БД. Не надо мудрить с выборками из абстрактного кэша.
Минус может быть в том, что тебе, может быть, хочется именно какой-то внешний кэш?

PS. Я просто сторонник того, чтобы максимум делать внутри БД, максимально используя ее возможности.

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.