Поиск на сайте с помощью phpMorphy
Всем привет!
Заметка скорее всего больше для размышлений, но может кому пригодится.
Тут между делом за поиск зацепились и Василий сказал, что использует Sphinx. Я со сфинксом столкнулся еще году в 2009-ом и тогда его с наскоку не победил, но для себя уяснил четко: он весьма не прост. Но когда в свое время решил на своем сайте сделать поиск, нужно было что-то искать на замену, ведь важная часть поиска — это именно морфологический поиск.
В поисках решения я набрел на phpMorphy (конкретно этот пакет устаревший уже, но есть и более новые реализации). Суть его в том, чтобы делать разбор строки и определять леммы.
И вот в результате появился компонент modSearch. Исходники его я выложил: github.com/MODX-Club/modsearch
Возможно будет интересно покопать отдельный моменты по реализации. Часть из них опишу.
1. Плагин. Срабатывает на сохранение документа (событие OnDocFormSave).
К сожалению, в самом классе документа нет вызова ивента при сохранении, чтобы плагин срабатывал на любое изменение, пусть даже через API
Для сравнения в классе modUser прописаны вызовы при сохранении: github.com/modxcms/revolution/blob/2.x/core/model/modx/moduser.class.php#L92-L114
То есть на пользователя можно навесить плагин, который всегда сработает где и как бы не был сохранен пользователь (исключая случаи выполнения чистого SQL).
Не буду говорить, что это еще один недостаток MODX.
2. Создание поисковых индексов. github.com/MODX-Club/modsearch/blob/master/core/components/modsearch/model/modsearch/modsearch.class.php#L16
В системной настройке modsearch.index_fields можно перечислить поля, которые будут использоваться для создания поисковых индексов. При создании индексов скрипт берет эту системную настройку и из документа дергает эти поля. По-умолчанию это pagetitle, longtitle, content.
3. Переобход всех документов, чтобы создать для них индексы (выполняется в консоли).
github.com/MODX-Club/modsearch/blob/master/core/components/console/files/global/modxclub.ru/modsearch/resources/update_indexes.php
4. Скрипт для поиска документов через процессор компонента modxSite (так же выполняется в консоли).
github.com/MODX-Club/modsearch/blob/master/core/components/console/files/global/modxclub.ru/modsearch/resources/getdata.php
А вот здесь вот формируется итоговый запрос на выборку документов: github.com/MODX-Club/modxSite/blob/master/core/components/modxsite/processors/site/web/resources/getdata.class.php#L64
5. Установка «на лету» связи modResource->SearchIndexes.
github.com/MODX-Club/modsearch/blob/master/core/components/modsearch/model/modsearch/metadata.mysql.php
Могу точно сказать, что с небольшими модификациями это можно использовать и с минишопом (делал на паре сторонних сайтов) и на каталоге в несколько тысяч товаров вполне приемлемо ищет, в том числе и по скорости.
Заметка скорее всего больше для размышлений, но может кому пригодится.
Тут между делом за поиск зацепились и Василий сказал, что использует Sphinx. Я со сфинксом столкнулся еще году в 2009-ом и тогда его с наскоку не победил, но для себя уяснил четко: он весьма не прост. Но когда в свое время решил на своем сайте сделать поиск, нужно было что-то искать на замену, ведь важная часть поиска — это именно морфологический поиск.
В поисках решения я набрел на phpMorphy (конкретно этот пакет устаревший уже, но есть и более новые реализации). Суть его в том, чтобы делать разбор строки и определять леммы.
И вот в результате появился компонент modSearch. Исходники его я выложил: github.com/MODX-Club/modsearch
Возможно будет интересно покопать отдельный моменты по реализации. Часть из них опишу.
1. Плагин. Срабатывает на сохранение документа (событие OnDocFormSave).
К сожалению, в самом классе документа нет вызова ивента при сохранении, чтобы плагин срабатывал на любое изменение, пусть даже через API
$doc = $modx->getObject("modResource", $id);
$doc->set("content", $newContent);
$doc->save();
То есть если обновить вот так, то плагин не сработает, он сработает только на сохранение документа через админку.Для сравнения в классе modUser прописаны вызовы при сохранении: github.com/modxcms/revolution/blob/2.x/core/model/modx/moduser.class.php#L92-L114
То есть на пользователя можно навесить плагин, который всегда сработает где и как бы не был сохранен пользователь (исключая случаи выполнения чистого SQL).
Не буду говорить, что это еще один недостаток MODX.
2. Создание поисковых индексов. github.com/MODX-Club/modsearch/blob/master/core/components/modsearch/model/modsearch/modsearch.class.php#L16
В системной настройке modsearch.index_fields можно перечислить поля, которые будут использоваться для создания поисковых индексов. При создании индексов скрипт берет эту системную настройку и из документа дергает эти поля. По-умолчанию это pagetitle, longtitle, content.
Здесь отдельно отмечу один из минусов моего решения: здесь нет никакого ранжирования. То есть не важно в заголовке слова были найдены или нет, вес их одинаковый. Или было найдено, или нет. С этой точки зрения у Василия конечно же лучше реализовано.
3. Переобход всех документов, чтобы создать для них индексы (выполняется в консоли).
github.com/MODX-Club/modsearch/blob/master/core/components/console/files/global/modxclub.ru/modsearch/resources/update_indexes.php
4. Скрипт для поиска документов через процессор компонента modxSite (так же выполняется в консоли).
github.com/MODX-Club/modsearch/blob/master/core/components/console/files/global/modxclub.ru/modsearch/resources/getdata.php
А вот здесь вот формируется итоговый запрос на выборку документов: github.com/MODX-Club/modxSite/blob/master/core/components/modxsite/processors/site/web/resources/getdata.class.php#L64
5. Установка «на лету» связи modResource->SearchIndexes.
github.com/MODX-Club/modsearch/blob/master/core/components/modsearch/model/modsearch/metadata.mysql.php
Могу точно сказать, что с небольшими модификациями это можно использовать и с минишопом (делал на паре сторонних сайтов) и на каталоге в несколько тысяч товаров вполне приемлемо ищет, в том числе и по скорости.
Комментарии: 16
mSearch2 с самого начала работает на phpMorphy.
Василий сказал, что использует SphinxТолько здесь, на modx.pro. Думал, что он получше mSearch2 работать будет, но пока что вышло, что это не так.
Ясно. Спасибо за уточнение.
P.S. про здесь сфинкс — я так и думал. Но не знал, что phpMorphy у тебя в mSearch2 используется.
P.S. про здесь сфинкс — я так и думал. Но не знал, что phpMorphy у тебя в mSearch2 используется.
А как насчет связки phpMorphy + Sphinx? Так же интересно узнать про опыт использования phpMorphy2 для нормализации контента под индексацию.
А как насчет связки phpMorphy + Sphinx?Не совсем понятно, как и зачем их связывать.
Sphinx — это отдельно крутящий демон, которому ты отдаёшь поисковый запрос и он делает всю работу. Включая, например, подсветку найденных слов.
Выглядит это примерно как SQL запрос, только не в БД, а в Sphinx
$query = (new SphinxQL($this->conn))
->select('id', 'comment', 'weight() AS weight')
->from('topics')
->limit($start, $limit)
->option('field_weights', [
'pagetitle' => 100,
'content' => 50,
'comment' => 10,
])
->groupBy('id')
->option('max_matches', 1000000)
->match(['pagetitle', 'content', 'comment'], $string);
$result = $query->execute();
В mSearch2 же это всё делается вручную, используя формы слов от phpMorphy. Наверное можно просклонять слова в phpMorphy, потом поискать их в Sphinx, потом отдельно отранжировать и соединить ответы — но вряд ли это что-то улучшит, а вот усложнит — наверняка.
Так же интересно узнать про опыт использования phpMorphy2Я такого не нашёл. Есть только pymorphy2, но он на Python и его ни разу не использовал.
Я знаю как работает Sphinx. Вопрос был в стеммерах и использовании в связке. Но я уже понял, что это не пробовалось.
Я такого не нашёл. Есть только pymorphy2, но он на Python и его ни разу не использовал.Его и имел в виду
Возможно я тебя удивлю, но в MODX у таблицы ресурсов есть могучий полнотекстовый индекс, который лопатить 5 полей ресурса при операциях CRUD. Почему никто не хочет его использовать? Даже разработчики. Why? ;)
Нет, ты меня совсем не удивишь этим. Но на мой костыль у меня есть несколько причин:
1. innoDB не умеет в fulltext habr.com/ru/post/114572/ А я часто перевожу базу данных на innoDB, потому что MyIsam не умеет в foreign key, да еще и постоянно разваливается.
2. Если я расширяю таблицу и добавляю кастомные поля, то и индекс надо расширять.
3. Я могу хотеть не учитывать некоторые колонки.
4. Я могу хотеть добавить индексы сразу по нескольким таблица.
1. innoDB не умеет в fulltext habr.com/ru/post/114572/ А я часто перевожу базу данных на innoDB, потому что MyIsam не умеет в foreign key, да еще и постоянно разваливается.
2. Если я расширяю таблицу и добавляю кастомные поля, то и индекс надо расширять.
3. Я могу хотеть не учитывать некоторые колонки.
4. Я могу хотеть добавить индексы сразу по нескольким таблица.
1. Уже давно умеет ))
Вот и я приблизительно также аргументировал PR с выпиливанием этого монстра. Но Джейсон сказал, что чем больше индексов тем лучше. Хрен с ним, что некоторые не используются. Когда-нибудь кому-нибудь пригодится. Fuck the fuel economy and sql optimization!
Вот и я приблизительно также аргументировал PR с выпиливанием этого монстра. Но Джейсон сказал, что чем больше индексов тем лучше. Хрен с ним, что некоторые не используются. Когда-нибудь кому-нибудь пригодится. Fuck the fuel economy and sql optimization!
1. Уже давно умеет ))Но так и я этот компонент писал давно :)
На тот момент я получал сообщение «Не могу создать такой индекс».
Спасибо за статью!
Я как раз хотел приступить к реализации морфологического поиска по своей кастомной таблице — тут много полезных моментов я нашел для себя!
Я как раз хотел приступить к реализации морфологического поиска по своей кастомной таблице — тут много полезных моментов я нашел для себя!
Пожалуйста!
на каталоге в несколько тысяч товаров вполне приемлемо ищетА несколько, это сколько? У меня msearch стоит на сайте с > 75 тысяч товаров (76 673 на данный момент), и поиск работает вполне приемлемо.
0.1394129: Total time
25 661 440: Memory usage
Как говорят программисты: работает? не лезь!
Так что если работает: то замечательно.
Но встречный вопрос: так работает из коробки или какая кастомизация выполнялась? Если кастомизация, то неплохо бы описать ее в отдельной статье. Но предполагаю, что кастомизации никакой особо не было (судя по объему потребляемой памяти). Значит просто сервер помощнее взят? Какие характеристики железа?
И если не сложно, кинь ссылку на свой магазин, чуть-чуть помучить его поисковыми запросами, чтобы посмотреть как быстро он работает.
Со своей стороны вот один из моих топиков про оптимизацию: modxclub.ru/blog/bolshoy-magazin-na-modx-revolution/172.html
Конкретно в этом топике ничего нет касаемого modSearch, но я когда тесты проводил, скорость при поиске не сильно отличалась.
Так что если работает: то замечательно.
Но встречный вопрос: так работает из коробки или какая кастомизация выполнялась? Если кастомизация, то неплохо бы описать ее в отдельной статье. Но предполагаю, что кастомизации никакой особо не было (судя по объему потребляемой памяти). Значит просто сервер помощнее взят? Какие характеристики железа?
И если не сложно, кинь ссылку на свой магазин, чуть-чуть помучить его поисковыми запросами, чтобы посмотреть как быстро он работает.
Со своей стороны вот один из моих топиков про оптимизацию: modxclub.ru/blog/bolshoy-magazin-na-modx-revolution/172.html
Конкретно в этом топике ничего нет касаемого modSearch, но я когда тесты проводил, скорость при поиске не сильно отличалась.
Из коробки, никакой оптимизации – evrorazbor.by, скорость устраивает, но были вопросы к точности результатов, поэтому для этого же сайта, но только российской версии используется другой evrorazbor.ru – чуть быстрее, но точность результатов гораздо лучше. Можно проверить разницу на запросе «акпп bmw», с ним хорошо видна разница.
неплохо бы описать ее в отдельной статьеВариант для российской версии сайта сделал @Володя, так что это к нему.
Значит просто сервер помощнее взят? Какие характеристики железа?6 x 2,4+ ГГц, 8192 МБ
Да нет, там время выполнения совсем не 0.1 сек. Простой запрос: evrorazbor.by/search?query=%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D0%B9+%D1%82%D0%BE%D1%80%D0%BC%D0%BE%D0%B7%D0%BD%D0%BE%D0%B9+%D0%B4%D0%B8%D1%81%D0%BA
3-4 секунды.
И да, сервер совсем не простой.
3-4 секунды.
И да, сервер совсем не простой.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.