Поиск Sphinx в Laravel

В процессе разработки веб-приложения на платформе Laravel 5.6, передо мной стала задача реализации полнотектового поиска. Было принято решение реализовывать его на поисковой машине Sphinx. Из Википедии:

Sphinx (англ. SQL Phrase Index) — система полнотекстового поиска, разработанная Андреем Аксёновым и распространяемая по лицензии GNU GPL. Отличительной особенностью является высокая скорость индексации и поиска, а также интеграция с существующими СУБД (MySQL, PostgreSQL) и API для распространённых языков веб-программирования (официально поддерживаются PHP, Python, Java; существуют реализованные сообществом API для Perl, Ruby,.NET[1] и C++);

Погуглив, что есть в интернете на эту тему, я пришел к выводу, что статей об установке и настройке Сфинкса много, а вот о том, как связать это дело с Laravel — ничего нету. По этому попробую заполнить этот пробел. Итак.

Установка Sphinx

Установка Sphinx на Ubuntu хорошечно описана здесь. Разве что к описанному конфигу, я бы добавил настройки морфологии поиска. Например секция Index из моего конфига:

index index_name
{
source            = src1
path              = /var/lib/sphinxsearch/data/index_name
morphology        = stem_enru
min_word_len      = 1
charset_type      = utf-8
docinfo           = extern
}

Что здесь есть хорошего?

morphology = stem_enru — Здесь мы задаем в качестве морфологии стемминг. Что это значит? Ну например если мы будем искать «задача», поисковая машина выдаст нам варианты: «задачи», «задач», «задаче». Можно задать стемминг как отдельно для языка, например «stem_en», «stem_ru», так и для обоих языков — «stem_enru». Больше о морфологии можно почитать Здесь.

min_word_len = 1 — минимальное количество символов для поиска.

charset_type = utf-8 — ну мы же как белые люди работаем в UTF-8, правильно?

Установка клиента

Клиентов Sphinx для Laravel — тьма тьмущая. Но я решил взять тот, который обновлялся последним. Это клиент «sngrl/sphinxsearch». Устанавливаем через композер:

composer require sngrl/sphinxsearch:dev-master

Далее прописываем сервис-провайдер в массив «providers» в config/app.php

'providers' => array(
        /*** тут какие-то другие провайдеры ***/
        sngrl\SphinxSearch\SphinxSearchServiceProvider::class,
    ),


Публикуем

php artisan vendor:publish --provider=sngrl\SphinxSearch\SphinxSearchServiceProvider --force

Тут должен был создаться конфигурационный файл, но лично у меня он почему-то не создался. Если у вас тоже, создаете ручками файл config/sphinxsearch.php. В нем пишем:

<?php
return array(
    'host'    => '192.168.10.10', //Такие же хост и порт у вас должны быть прописаны в конфиге Сфинкса
    'port'    => 9312, //для данной конфигурации соответственно listen = 192.168.10.10:9312
    'timeout' => 30,
    'indexes' => array(
        'index_name' => array ( 'table' => 'table_name', 'column' => 'column_name' )
    )
);

index_name — тот же самый, который мы прописывали в конфиге. table_name — имя таблицы из которой мы будем делать выборку. column_name — поле по которому мы будем делать выборку (скорее всего там будет id).

В контроллере пишем:

$sphinx  = new SphinxSearch();
$results = $sphinx->search($query, 'index_name')//$query - наша поисковая фраза, index_name - всё тот же, что мы указывали в конфиге выше
            ->setFieldWeights(//Приоритет полей при выдаче
                array(
                    'title' => 10,//Ну к примеру
                    'text'  => 8
                )
            )
            ->get();


Или проще:

$results = $sphinx->search('my query', 'index_name')->get();

Вот еще вариант с лимитами и фильтрами:

$results = $sphinx->search('my query', 'index_name')
	->limit(30)
	->filter('attribute', array(1, 2))
	->range('int_attribute', 1, 10)
	->get();

С сортировкой:

$result = $sphinx->search('my query', 'index_name')
	->setFieldWeights(
		array(
			'partno'  => 10,
			'name'    => 8,
			'details' => 1
		)
	)
	->setMatchMode(\Sphinx\SphinxClient::SPH_MATCH_EXTENDED)
	->setSortMode(\Sphinx\SphinxClient::SPH_SORT_EXTENDED, "@weight DESC")
	->get(true);  //passing true causes get() to respect returned sort order

Можно комбинировать. При использовании метода ->get (), мы получаем полноценную коллекцию моделей, которую мы можем сразу отправлять во вьюху. Если же нам нужно получить только прямой ответ от Сфинкса, используем метод ->query ()

$results = $sphinx->search('my query', 'index_name')->query();

Вы великолепны!

Добавить комментарий