В процессе разработки веб-приложения на платформе 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();
Вы великолепны!