В предыдущей статье я описывал как установить и использовать Sphinx для поиска в Yii2.
Теперь задача: используя Yii2 сделать поисковый запрос к Sphinx, подсветить поисковые слова (snippets, excerpts) и вывести их по 10 на страницу.
- Подключаем расширение yiisoft/yii2-sphinx
- Выполняем запрос (индекс предварительно настроен и работоспособность проверена)
$sql = "SELECT id, type_id, SNIPPET(title, :q) as _title, SNIPPET(content, :q) AS _content FROM index WHERE MATCH(:q)";
$rows = Yii::$app->sphinx->createCommand($sql)
->bindValue('q', Yii::$app->sphinx->escapeMatchValue($q))
->queryAll();
Где index
— ваш поисковый индекс.
Что бы Sphinx вернул столбец с именем и при этом полноценно производил полнотекстовый поиск по нему, нужно использовать типsql_field_string
для полей title
и content
из примера.
Из документации:
sql_attr_string only stores the column value but does not full-text index it. In some cases it might be desired to both full-text index the column and store it as attribute. sql_field_string lets you do exactly that. Both the field and the attribute will be named the same.
Таким образом настроив конфиг
sql_query = SELECT id, type_id, title, content \
FROM table \
WHERE id >= $start AND id <= $end
sql_query_range = SELECT MIN(id),MAX(id) FROM table
sql_attr_uint = type_id
sql_field_string = title # will be both indexed and stored
sql_field_string = content
Мы получаем возможность используя 1 запрос получить список ID записей удовлетворяющих результатам, а также получить дополнительные атрибуты содержащие подсвеченные поисковые слова (highlighted).
На выходе у нас массив записей, содержащий
array (size=3)
0 => array
'id' => string '1'
'type_id' => string '3'
'_title' => string 'Текст <b>выделение</b> текст'
'_content' => string ' ... текст <b>выделение</b> другой текст... '
1 => array
'id' => string '2'
'type_id' => string '3'
'_title' => string '... <b>выделение</b>'
'_content' => string 'Текст выделен только в заголовке '
2 =>
...
Теперь вывести результат и разбить постранично — дело техники.
Привожу полный код:
public function actionSearch($q = '')
{
$q = Yii::$app->sphinx->escapeMatchValue($q);
$sql = "SELECT id, type_id, SNIPPET(title, :q) as _title, SNIPPET(content, :q) AS _content FROM Index WHERE MATCH(:q)";
$rows = Yii::$app->sphinx->createCommand($sql)
->bindValue('q', $q)
->queryAll();
$snippets = [];
foreach ($rows as $row) {
$snippets[$row['id']] = ['title' => $row['_title'], 'content' => $row['_content']];
}
$pagination = new Pagination([
'defaultPageSize' => 5,
'totalCount' => count($rows),
]);
$model = Table::find()
->where(['id' => array_keys($snippets)])
->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render('search', ['q' => $q, 'model' => $model, 'snippets' => $snippets, 'pagination' => $pagination]);
}
Надеюсь материал будет вам полезен.
PS. Надо помнить, что все атрибуты сфинкс держит всегда в оперативной памяти, поэтому если вы насоздаете много строковых атрибутов у вас могут возникнуть проблемы с оперативкой.