Авг 16, 2007
Поиск с русской морфологией средствами PHP
На мой взгляд любой поиск по сайту должен обладать русской морфологией. На деле лишь единицы из проектов обладают этой возможностью. Разработчики ссылаются на сложность разработки и я до сего дня думал так же. На деле все оказалось проще — есть готовые словари. К примеру, .
Данный проект незаслуженно забыт программистами, хотя является удобным средством для организации поиска по сайту с учетом морфологии русского, английского или немецкого языков. Словари на каждый язык занимают порядка 2 Мб, сам скрипт — около 20 Кб. В составе phpMorphy нет инструментария дла работы с базой данных — его придется написать самостоятельно. Но в нем есть самое ценное:
- Определение словоформ указанного слова;
- Определение корня слова;
- Определение начальной формы слова.
Этого хватит слихвой для создания более-менее адекватного поиска. Лично я использовал определение корня слова, а затем каждый корень искал в полях, к примеру, так:
SELECT * FROM `tbl1` WHERE UPPER(`col1`) LIKE ‘%АФИШ%’;
UPPER() используется из-за того, что phpMorphy возвращает все слова в верхнем регистре.
Как я понял, последние версии phpMorphy не работают на PHP4, поэтому стоит начать миграцию на PHP5, хотя если ваши скрипты обновляются более-менее часто, правки будут незначительны.
Подготовка текста
Для обработки введенной пользователем строки удобно пользоваться регулярными выражениями — пример есть на .
Работа со словарями
Для начала нужно скачать требуемые словари (на ваш выбор — , , ) и для работы с ними.
Распаковав модули, у нас получаются файлы со справкой, а также 3 папки: dicts, src и examples. В первую нужно распаковать словари, во второй находятся модули для работы со словарями, а в третьей — пример использования phpMorphy.
Приводить текст примера не буду, вы можете увидеть его самостоятельно. Остановлюсь лишь на его ключевых моментах.
Все, что находится выше строки:
// Hint: in this example words $word_one, $word_two are in russian language(cp1251 encoding)
используется для инициализации словарей. Там ничего не нужно править. Исключение составляют закомментированныя строки:
// $codepage = $morphy->getCodepage();
// setlocale(LC_CTYPE, array(‘ru_RU.CP1251′, ‘Russian_Russia.1251′));
которые в случае необходимости правите для изменения рабочей кодировки — в немецком это cp1252, а в английском cp1250. Но наверняка вам это не понадобится.
Ниже идет пример работы. У phpMorphy есть 2 режима работы — одиночный (single mode) и блочный (bulk mode). Первый используется для обработки каждого слова по отдельности, второй — для обработки целого массива слов. Остановимся на втором, как наиболее удобном, по крайней мере на мой взгляд.
Для начала задаем входные слова:
$word_one = ‘ПРОВЕРКА’;
$word_two = ‘МОРФОЛОГИЗАТОРА’;
…
$bulk_words = array($word_one, $word_two);
С помощью phpMorphy мы можем получить у них начальную форму:
$base_form = $morphy->getBaseForm($bulk_words);
получить все словоформы:
$all_forms = $morphy->getAllForms($bulk_words);
или получить корень слова:
$pseudo_root = $morphy->getPseudoRoot($bulk_words);
Что для вас — ваш выбор. Я остановился на определении корня слова — максимально короткий SQL-запрос при аналогичной точности выборки.
В качестве результата возвращается массив, который мы можем использовать для поиска. К примеру, так:
$request_words = array();
$columns = array(«title», «description»);
foreach($pseudo_root as $group_form)
if($group_form)
foreach($group_form as $one_form)
foreach($columns as $col)
$request_words[] = «UPPER(`».$col.»`) LIKE ‘%».$one_form.»%’»;
$request = «SELECT * FROM `tbl1` WHERE («.join(» OR «,$request_words).»);»;
Дам комментарий — в $columns мы указываем список полей таблицы, по которым производим поиск. В $request, соответственно, формируется окончательный SQL-запрос, который остается лишь выполнить.
PS Попробовать поиск можно на . На данный момент результаты сотрируются по рейтингу сайта, но несложно организовать сортировку и по релевантности. Если кому-то нужны полные листинги — .
thnx! Очень сильно помогло.
Спасибо, очень полезная статья.
Спасибо за статью, есть вопрос:
я так понял, что словарь русский в кодировке ср1251, а у меня в базе данные в UTF-8 для правильной работы скрипта надо наверное перевести словарь в UTF-8? Если да, то как это сделать? Заранее спасибо.
Да, используй iconv
Спасибо за очень полезную статью.
какие еще функции есть, прсто методом тыка сидеть и перебирать методы не есть хорошо…
«Лично я использовал определение корня слова, а затем каждый корень искал в полях»
Если слов будет достаточно много, и для каждого искать через LIKE соответствующие записи будет большая нагрузка на БД.
С корнем в русском языке бывают большие сложности. А для снижения нагрузки исплользуют конструкцию match… against. Но для этого обязательно нужно создать полнотекстовые индексы для соответствующих полей таблиц.
А существует ли что-либо на перле ?
Для перла легко прикручивается mystem от яндекса ()
Для пхп тоже, кстати, его можно использовать, но в случае провайдерского запрета на системные вызовы придется дописать обертку (на том же перле
)
— более актуальная ссылка на скачку
Интересный класс.
Только запрос вида LIKE ‘%string%’ может очень сильно снизить производительность…
Большое спасибо за прекрасную статью. Вы мне очень помогли!
Любопытная хрень, однако… Не думал, что на халяву можно такую базу отыметь… Одна проблема — запросы по шаблону кромешно грузят базу. WHERE MATCH гораздо экономичней, да и сортирует в зависимости от плотности искомых слов… Однако ищет только по полному слову, а не по части

Какие идеи? Заслать запрос с WHERE MATCH (…) OR WHERE MATCH (…) со всеми вариантами слова?.. А если ищется БОЛЬШАЯ фраза?..
Есть идеи?
к сожалению, проект вроде как уже давно не поддерживается, но все равно спасибо за полезный материал!