Использование системы полнотекстового поиска Sphinx с поддержкой морфологии позволяет добиться высокой скорости индексации и поиска, а также снижения потребления ресурсов сервера.
Sphinx доступен на большинстве платформ, исчерпывающая информация доступна на сайте производителя - установка на Debian и Ubuntu, установка на CentOS и RedHat, установка на Windows.
Для использования мы рекомендуем версию 2.2.10 и старше.
В конфигурационный файл sphinx.conf внесите новый индекс, в данном примере он называется hostcms:
index hostcms {
type = rt
path = /var/lib/sphinx/hostcms
rt_mem_limit = 64M
morphology = stem_enru, soundex
rt_field = title
rt_field = text
rt_attr_string = title
rt_attr_timestamp = datetime
rt_attr_string = url
rt_attr_uint = size
rt_attr_uint = inner
rt_attr_multi = siteuser_group_id
rt_attr_uint = module
rt_attr_uint = module_id
rt_attr_uint = module_value_type
rt_attr_uint = module_value_id
rt_attr_uint = site_id
}
Путь размещения индекса path может варьироваться в зависимости от используемой ОС. Не забудьте проверить соответствие владельцев директории, указанной в пути, и пользователя, от которого работает searchd.
В секции searchd настройте опцию listen, которая задается в формате listen = ( address ":" port | port | path ) [ ":" protocol ]
searchd
{
listen = localhost:9312:mysql41
...
}
Далее перезагрузите sphinxd и проверьте наличие соединения:
/etc/init.d/searchd restart
Проверьте корректность соединения с Sphinx:
mysql -h 127.0.0.1 -P 9312
В конфигурационном файле модуля поиска в секции default укажите использования драйвера sphinx и задайте параметры:
<?php
return array (
'default' => array(
'driver' => 'sphinx',
'database' => 'sphinx',
'index' => 'hostcms'
),
'modules' => array(
0 => 'Structure',
1 => 'Informationsystem',
2 => 'Forum',
3 => 'Shop',
4 => 'Helpdesk',
5 => 'Siteuser'
)
);
В конфигурационном файле баз данных добавьте параметры нового соединения sphinx, указанного выше в опции database:
<?php
return array(
'default' => array(
...
),
'sphinx' => array(
'driver' => 'pdo',
'host' => '127.0.0.1:9312',
'database' => NULL
)
);
В случае изменения конфигурационного файла sphinx.conf мы рекомендуем остановить searchd, удалить файлы индекса (в данном примере файлы hostcms* в /var/lib/sphinx) и запустить searchd.
Морфологические словари позволяют улучшить качество поиска, т.к. вместо нахождения основы слова используется нормальная словарная форма.
Слово | Стеммер | Словарь |
---|---|---|
Диплом | Дипл | Диплом |
Диплома | Диплом | Диплом |
Груша | Груш | Груша |
Создайте директорию /etc/sphinx/dic/
и загрузите в нее требуемые словари.
В конфигурационный файл sphinx.conf внесите следующие изменения:
index hostcms {
...
#morphology = stem_enru, soundex
morphology = lemmatize_ru_all, lemmatize_en_all
...
}
indexer
{
...
lemmatizer_cache = 64M
}
common
{
lemmatizer_base = /etc/sphinx/dic/
}
Перезагрузите sphinxd и проверьте работу:
/etc/init.d/searchd restart
В случае необходимости вносить изменения в результаты поиска на основе собственных весов, например, разместить товары, которых нет в наличии, в самом конце поисковой выдачи, вы можете использовать собственное поле, в которое будете вносить вес, а затем задать формулу расчета веса при поиске.
Внесем в конфигурационный файл после после rt_attr_uint = site_id добавим новое поле rt_attr_float = myweight (также см. выше "Удаление индекса при внесении изменений в sphinx.conf").
В приведенном ниже примере для товаров, которые отсутствуют на складе, устанавливается myweight в 0, а для товаров в наличии 1. Затем используется формула расчета веса, в которой к рассчитанном Sphinx-ом весу прибавляется myweight*10.
class Sphinx_Observer { static public function onAfterPrepareQueryBuilder($object, $args) { $queryBuilder = $args[0]; $queryBuilder->columns('myweight'); } static public function onAfterPrepareValues($object, $args) { $aValues = $args[0]; $oPage = $args[1]; // Товар магазина if ($oPage->module == 3 && $oPage->module_value_type == 2) { $oShop_Item = Core_Entity::factory('Shop_Item', $oPage->module_value_id); $myweight = $oShop_Item->getRest() <= 0 ? 0 : 1; } else { $myweight = 1; } $aValues[] = $myweight; return $aValues; } static public function onBeforeExecuteFind($object, $args) { $oSearch_Sphinx_QueryBuilder_Select = $args[1]; // http://sphinxsearch.com/docs/current/sphinxql-select.html // http://sphinxsearch.com/docs/current/formulas-for-builtin-rankers.html /* SPH_RANK_PROXIMITY_BM25 = sum(lcs*user_weight)*1000+bm25 SPH_RANK_BM25 = bm25 SPH_RANK_NONE = 1 SPH_RANK_WORDCOUNT = sum(hit_count*user_weight) SPH_RANK_PROXIMITY = sum(lcs*user_weight) SPH_RANK_MATCHANY = sum((word_count+(lcs-1)*max_lcs)*user_weight) SPH_RANK_FIELDMASK = field_mask SPH_RANK_SPH04 = sum((4*lcs+2*(min_hit_pos==1)+exact_hit)*user_weight)*1000+bm25 */ //$oSearch_Sphinx_QueryBuilder_Select->option('ranker', "expr('sum(lcs*user_weight)*1000+bm25')") //$oSearch_Sphinx_QueryBuilder_Select->option('ranker', "expr('sum((word_count+(lcs-1)*max_lcs)*user_weight)+myweight*2')"); $oSearch_Sphinx_QueryBuilder_Select->option('field_weights', "(title=2)"); $oSearch_Sphinx_QueryBuilder_Select->option('ranker', "expr('sum(lcs*user_weight) + myweight*10')"); } } Core_Event::attach('Search_Controller_Sphinx.onAfterPrepareQueryBuilder', array('Sphinx_Observer', 'onAfterPrepareQueryBuilder')); Core_Event::attach('Search_Controller_Sphinx.onAfterPrepareValues', array('Sphinx_Observer', 'onAfterPrepareValues')); Core_Event::attach('Search_Controller_Sphinx.onBeforeExecuteFind', array('Sphinx_Observer', 'onBeforeExecuteFind'));