Как правильно реализовать фильтры по свойствам в Sphinx?

Переписываю сайт доски объявлений с mySQL на SphinxSE - делаю на фреймворке Yii2 (yii\sphinx\Query)
Опишу суть вопроса на упрощенном примере...

В mySQL Б.Д. есть таблицы `announces` и `options`, в первой лежат объявления (заголовок, текст, дата подачи и т.д.), во второй - свойства (имя_свойства, значение), связь один ко многим:
`announces`.`id` -> `options`.ann_id

В настройках индекса Sphinx я поступил так:

source announces
{
     sql_query	  = \
        SELECT `announces`.`id`, `announces`.`header`, `announces`.`description`, \ 
       (SELECT JSON_OBJECTAGG(`option_id`, `value`) FROM `options` WHERE `options`.`ann_id` = `announces`.`id`) AS `filters`, \
       и т.д.
      
      sql_field_string = header
      sql_field_string = description 
      sql_attr_json = filters
}


В результате я получаю в индексе `announces` поле в формате jSON - например так:

[filters] => {"422":"Toyota","423":"Prius","424":"Гибрид","425":"Автомат","426":"Передний","427":"Хэтчбэк","429":"Серый","430":1800,"431":2019]


Теперь я могу фильтровать по свойствам, например так:
$query = new Query(); // Sphinx
        $query->from('announces')
              ->where(['disabled' => 0])
             ->andWhere( "filters['424'] = 'Гибрид'" )
            ->all();


Так я получаю что нужно...
А теперь проблема... Мне нужно использовать IN, чтобы проверить наличие одного из вариантов в jSON
Так, я пробовал вариант:

->andWhere( " filters['424'] IN ( 'Бензин', 'Дизель', 'Газ' ) ") // Так не ищет в jSON :(


Другой вариант - использовать под циклом OR внутри IN - но он мне не нравится... Фильтров очень много, - это упрощенный пример...
  • Вопрос задан
  • 327 просмотров
Решения вопроса 1
tumbler
@tumbler
бекенд-разработчик на python
В оригинале IN используется как функция, попробуйте.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
atillus
@atillus Автор вопроса
Сергей Тихонов, да, - спасибо!
Это работает. так:

$query = new Query(); // Sphinx
$query->from('announces');
$query->addSelect("*");
$query->addSelect(new Expression("IN(filters['424'], 'Бензин', 'Дизель', 'Газ') AS f_424"));
$query->andWhere("f_424 = 1");
$query-all();


... тут всё ОК

Но теперь новая проблема... - с разбивкой для пагинации...
Перед вызовом $query->all() нужно подсчитать общее кол-во и добавить limit и offset
Попытка посчитать $total = $query->count(); - даёт ошибку "no such filter attribute 'f_425'", т.к. запрос на он выполняет такой: SELECT COUNT(*) FROM `announcements` WHERE ...... AND (f_425 = 1)
Ответ написан
Ваш ответ на вопрос

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

Похожие вопросы